diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..e6f4bef Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b5281fe --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/vendor +/node_modules \ No newline at end of file diff --git a/artisan b/artisan new file mode 100644 index 0000000..67a3329 --- /dev/null +++ b/artisan @@ -0,0 +1,53 @@ +#!/usr/bin/env php +make(Illuminate\Contracts\Console\Kernel::class); + +$status = $kernel->handle( + $input = new Symfony\Component\Console\Input\ArgvInput, + new Symfony\Component\Console\Output\ConsoleOutput +); + +/* +|-------------------------------------------------------------------------- +| Shutdown The Application +|-------------------------------------------------------------------------- +| +| Once Artisan has finished running, we will fire off the shutdown events +| so that any final work may be done by the application before we shut +| down the process. This is the last thing to happen to the request. +| +*/ + +$kernel->terminate($input, $status); + +exit($status); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..6013a37 --- /dev/null +++ b/composer.json @@ -0,0 +1,37 @@ +{ + "name": "vsmov/vsmov-core", + "description": "VsMov's core features", + "type": "library", + "authors": [ + { + "name": "vsmov", + "email": "vsmov@gmail.com" + } + ], + "require": { + "laravel/framework": "^6|^7|^8", + "ckfinder/ckfinder-laravel-package": "v3.5.2.1", + "vsmov/laravel-caching-model": "^1.0.0", + "vsmov/crud": "^1.0.0", + "vsmov/settings": "^1.0.0", + "vsmov/permissionmanager": "^1.0.0", + "spatie/laravel-sitemap": "^5.8", + "artesaos/seotools": "^v0.22.1" + }, + "license": "MIT", + "autoload": { + "psr-4": { + "VsMov\\Core\\": "src/", + "VsMov\\Core\\Database\\Factories\\": "database/factories/", + "VsMov\\Core\\Database\\Seeders\\": "database/seeders/" + } + }, + "extra": { + "laravel": { + "providers": [ + "VsMov\\Core\\VsMovServiceProvider" + ] + } + }, + "minimum-stability": "stable" +} diff --git a/config/config.php b/config/config.php new file mode 100644 index 0000000..1c26ede --- /dev/null +++ b/config/config.php @@ -0,0 +1,24 @@ + explode('@', \PackageVersions\Versions::getVersion('vsmov/vsmov-core') ?? 0)[0], + 'episodes' => [ + 'types' => [ + 'embed' => 'Nhúng', + 'mp4' => 'MP4', + 'm3u8' => 'M3U8' + ] + ], + 'ckfinder' => [ + 'loadRoutes' => false, + 'backends' => [ + 'name' => 'default', + 'adapter' => 'local', + 'baseUrl' => '/storage/', + 'root' => public_path('/storage/'), + 'chmodFiles' => 0777, + 'chmodFolders' => 0755, + 'filesystemEncoding' => 'UTF-8' + ] + ] +]; diff --git a/database/factories/ActorFactory.php b/database/factories/ActorFactory.php new file mode 100644 index 0000000..ce2f5dc --- /dev/null +++ b/database/factories/ActorFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/factories/CategoryFactory.php b/database/factories/CategoryFactory.php new file mode 100644 index 0000000..4018dbd --- /dev/null +++ b/database/factories/CategoryFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/factories/DirectorFactory.php b/database/factories/DirectorFactory.php new file mode 100644 index 0000000..e027337 --- /dev/null +++ b/database/factories/DirectorFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/factories/EpisodeFactory.php b/database/factories/EpisodeFactory.php new file mode 100644 index 0000000..1d66827 --- /dev/null +++ b/database/factories/EpisodeFactory.php @@ -0,0 +1,30 @@ + $name = rand(1, 5), + 'slug' => Str::slug('tap-' . $name), + ]; + } +} diff --git a/database/factories/MovieFactory.php b/database/factories/MovieFactory.php new file mode 100644 index 0000000..26095f1 --- /dev/null +++ b/database/factories/MovieFactory.php @@ -0,0 +1,31 @@ + $name = $this->faker->name, + 'origin_name' => $name, + 'slug' => Str::slug($name.microtime(true)), + ]; + } +} diff --git a/database/factories/RegionFactory.php b/database/factories/RegionFactory.php new file mode 100644 index 0000000..4549c2f --- /dev/null +++ b/database/factories/RegionFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/factories/StudioFactory.php b/database/factories/StudioFactory.php new file mode 100644 index 0000000..dd95101 --- /dev/null +++ b/database/factories/StudioFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/factories/TagFactory.php b/database/factories/TagFactory.php new file mode 100644 index 0000000..efbf342 --- /dev/null +++ b/database/factories/TagFactory.php @@ -0,0 +1,30 @@ + $name = $this->faker->name, + 'slug' => Str::slug($name), + ]; + } +} diff --git a/database/migrations/2015_08_04_131614_create_menus_table.php b/database/migrations/2015_08_04_131614_create_menus_table.php new file mode 100644 index 0000000..bfd45b6 --- /dev/null +++ b/database/migrations/2015_08_04_131614_create_menus_table.php @@ -0,0 +1,39 @@ +increments('id'); + $table->string('name', 100); + $table->string('type', 20)->nullable(); + $table->string('link', 255)->nullable(); + $table->integer('parent_id')->unsigned()->nullable(); + $table->integer('lft')->unsigned()->nullable(); + $table->integer('rgt')->unsigned()->nullable(); + $table->integer('depth')->unsigned()->nullable(); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('menus'); + } +} diff --git a/database/migrations/2015_08_04_131614_create_settings_table.php b/database/migrations/2015_08_04_131614_create_settings_table.php new file mode 100644 index 0000000..30c6a03 --- /dev/null +++ b/database/migrations/2015_08_04_131614_create_settings_table.php @@ -0,0 +1,40 @@ +increments('id'); + $table->string('key')->unique(); + $table->string('name'); + $table->string('description')->nullable(); + $table->text('value')->nullable(); + $table->text('field'); + $table->string('group')->nullable()->index(); + $table->boolean('active')->index(); + $table->timestamps(); + + $table->index(['group', 'active']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('settings'); + } +} diff --git a/database/migrations/2020_03_31_114745_remove_backpackuser_model.php b/database/migrations/2020_03_31_114745_remove_backpackuser_model.php new file mode 100644 index 0000000..1539c78 --- /dev/null +++ b/database/migrations/2020_03_31_114745_remove_backpackuser_model.php @@ -0,0 +1,54 @@ +replaceModels($model_has_roles); + } + if (\Illuminate\Support\Facades\Schema::hasTable($model_has_permissions)) { + $this->replaceModels($model_has_permissions); + } + } + + public function replaceModels($table_name) + { + Log::info('Replacing BackpackUser model in '.$table_name); + + // if you've ended up with duplicate entries (both for App\User and App\Models\BackpackUser) + // we can just delete them + $userEntries = DB::table($table_name) + ->where('model_type', "App\User") + ->get(); + + foreach ($userEntries as $entry) { + DB::table($table_name) + ->where('role_id', $entry->role_id) + ->where('model_type', 'App\Models\BackpackUser') + ->where('model_id', $entry->model_id) + ->delete(); + } + + // for the rest of them, we can just replace the BackpackUser model with User + DB::table($table_name) + ->where('model_type', "App\Models\BackpackUser") + ->update([ + 'model_type' => "App\User", + ]); + } +} diff --git a/database/migrations/2022_07_09_153613_create_themes_table.php b/database/migrations/2022_07_09_153613_create_themes_table.php new file mode 100644 index 0000000..610426d --- /dev/null +++ b/database/migrations/2022_07_09_153613_create_themes_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('name')->index(); + $table->string('display_name'); + $table->string('preview_image')->nullable(); + $table->string('author'); + $table->string('package_name'); + $table->text('value')->nullable(); + $table->boolean('active')->default(false); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('themes'); + } +} diff --git a/database/migrations/2022_07_10_125114_create_permission_tables.php b/database/migrations/2022_07_10_125114_create_permission_tables.php new file mode 100644 index 0000000..04c3278 --- /dev/null +++ b/database/migrations/2022_07_10_125114_create_permission_tables.php @@ -0,0 +1,141 @@ +bigIncrements('id'); // permission id + $table->string('name'); // For MySQL 8.0 use string('name', 125); + $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); + $table->timestamps(); + + $table->unique(['name', 'guard_name']); + }); + + Schema::create($tableNames['roles'], function (Blueprint $table) use ($teams, $columnNames) { + $table->bigIncrements('id'); // role id + if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing + $table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable(); + $table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index'); + } + $table->string('name'); // For MySQL 8.0 use string('name', 125); + $table->string('guard_name'); // For MySQL 8.0 use string('guard_name', 125); + $table->timestamps(); + if ($teams || config('permission.testing')) { + $table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']); + } else { + $table->unique(['name', 'guard_name']); + } + }); + + Schema::create($tableNames['model_has_permissions'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index'); + + $table->foreign(PermissionRegistrar::$pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } else { + $table->primary([PermissionRegistrar::$pivotPermission, $columnNames['model_morph_key'], 'model_type'], + 'model_has_permissions_permission_model_type_primary'); + } + + }); + + Schema::create($tableNames['model_has_roles'], function (Blueprint $table) use ($tableNames, $columnNames, $teams) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); + + $table->string('model_type'); + $table->unsignedBigInteger($columnNames['model_morph_key']); + $table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index'); + + $table->foreign(PermissionRegistrar::$pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + if ($teams) { + $table->unsignedBigInteger($columnNames['team_foreign_key']); + $table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index'); + + $table->primary([$columnNames['team_foreign_key'], PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } else { + $table->primary([PermissionRegistrar::$pivotRole, $columnNames['model_morph_key'], 'model_type'], + 'model_has_roles_role_model_type_primary'); + } + }); + + Schema::create($tableNames['role_has_permissions'], function (Blueprint $table) use ($tableNames) { + $table->unsignedBigInteger(PermissionRegistrar::$pivotPermission); + $table->unsignedBigInteger(PermissionRegistrar::$pivotRole); + + $table->foreign(PermissionRegistrar::$pivotPermission) + ->references('id') // permission id + ->on($tableNames['permissions']) + ->onDelete('cascade'); + + $table->foreign(PermissionRegistrar::$pivotRole) + ->references('id') // role id + ->on($tableNames['roles']) + ->onDelete('cascade'); + + $table->primary([PermissionRegistrar::$pivotPermission, PermissionRegistrar::$pivotRole], 'role_has_permissions_permission_id_role_id_primary'); + }); + + app('cache') + ->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null) + ->forget(config('permission.cache.key')); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + $tableNames = config('permission.table_names'); + + if (empty($tableNames)) { + throw new \Exception('Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.'); + } + + Schema::drop($tableNames['role_has_permissions']); + Schema::drop($tableNames['model_has_roles']); + Schema::drop($tableNames['model_has_permissions']); + Schema::drop($tableNames['roles']); + Schema::drop($tableNames['permissions']); + } +} diff --git a/database/migrations/2022_07_10_153442_create_categories_table.php b/database/migrations/2022_07_10_153442_create_categories_table.php new file mode 100644 index 0000000..5527344 --- /dev/null +++ b/database/migrations/2022_07_10_153442_create_categories_table.php @@ -0,0 +1,38 @@ +bigIncrements('id'); + $table->string('name')->unique(); + $table->string('slug')->unique()->index(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->unsignedBigInteger('user_id')->nullable()->index(); + $table->string('user_name')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('categories'); + } +} diff --git a/database/migrations/2022_07_10_153517_create_actors_table.php b/database/migrations/2022_07_10_153517_create_actors_table.php new file mode 100644 index 0000000..1736c67 --- /dev/null +++ b/database/migrations/2022_07_10_153517_create_actors_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('name'); + $table->string('name_md5')->unique(); + $table->string('slug')->index(); + $table->enum('gender', ['male', 'female', 'other'])->nullable(); + $table->string('bio')->nullable(); + $table->string('thumb_url', 2048)->nullable(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('actors'); + } +} diff --git a/database/migrations/2022_07_10_153517_create_directors_table.php b/database/migrations/2022_07_10_153517_create_directors_table.php new file mode 100644 index 0000000..e2d4b91 --- /dev/null +++ b/database/migrations/2022_07_10_153517_create_directors_table.php @@ -0,0 +1,40 @@ +id(); + $table->string('name'); + $table->string('name_md5')->unique(); + $table->string('slug')->index(); + $table->enum('gender', ['male', 'female', 'other'])->nullable(); + $table->string('bio')->nullable(); + $table->string('thumb_url', 2048)->nullable(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('directors'); + } +} diff --git a/database/migrations/2022_07_10_153517_create_regions_table.php b/database/migrations/2022_07_10_153517_create_regions_table.php new file mode 100644 index 0000000..b605f55 --- /dev/null +++ b/database/migrations/2022_07_10_153517_create_regions_table.php @@ -0,0 +1,38 @@ +bigIncrements('id'); + $table->string('name')->unique(); + $table->string('slug')->unique()->index(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->unsignedBigInteger('user_id')->nullable()->index(); + $table->string('user_name')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('regions'); + } +} diff --git a/database/migrations/2022_07_10_153517_create_studios_table.php b/database/migrations/2022_07_10_153517_create_studios_table.php new file mode 100644 index 0000000..8dc9663 --- /dev/null +++ b/database/migrations/2022_07_10_153517_create_studios_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('name'); + $table->string('name_md5')->unique(); + $table->string('slug')->index(); + $table->string('thumb_url', 2048)->nullable(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('studios'); + } +} diff --git a/database/migrations/2022_07_10_153517_create_tags_table.php b/database/migrations/2022_07_10_153517_create_tags_table.php new file mode 100644 index 0000000..18b2536 --- /dev/null +++ b/database/migrations/2022_07_10_153517_create_tags_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('name'); + $table->string('name_md5')->unique(); + $table->string('slug')->index(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('tags'); + } +} diff --git a/database/migrations/2022_07_10_153613_create_movies_table.php b/database/migrations/2022_07_10_153613_create_movies_table.php new file mode 100644 index 0000000..ee1687a --- /dev/null +++ b/database/migrations/2022_07_10_153613_create_movies_table.php @@ -0,0 +1,69 @@ +id(); + $table->string('name', 1024); + $table->string('origin_name', 1024); + $table->string('slug')->unique(); + $table->text('content')->nullable(); + $table->string('thumb_url', 2048)->nullable(); + $table->string('poster_url', 2048)->nullable(); + $table->enum('type', ['single', 'series']); + $table->enum('status', ['trailer', 'ongoing', 'completed']); + $table->string('trailer_url', 2048)->nullable(); + $table->string('episode_time')->nullable(); + $table->string('episode_current')->nullable(); + $table->string('episode_total')->nullable(); + $table->string('quality')->nullable()->default('HD'); + $table->string('language')->nullable()->default('Vietsub'); + $table->string('notify', 512)->nullable(); + $table->string('showtimes', 512)->nullable(); + $table->integer('publish_year')->index()->nullable(); + $table->boolean('is_shown_in_theater')->default(false); + $table->boolean('is_recommended')->default(false); + $table->boolean('is_copyright')->default(false); + $table->boolean('is_sensitive_content')->default(false); + + $table->integer('episode_server_count')->default(0); + $table->integer('episode_data_count')->default(0); + + $table->integer('view_total')->default(0); + $table->integer('view_day')->default(0); + $table->integer('view_week')->default(0); + $table->integer('view_month')->default(0); + $table->integer('rating_count')->default(0); + $table->decimal('rating_star', 3, 1)->default(0); + + $table->string('update_handler', 1024)->nullable(); + $table->string('update_identity', 2048)->nullable(); + $table->string('update_checksum', 2048)->nullable(); + + $table->unsignedBigInteger('user_id')->nullable()->index(); + $table->string('user_name')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('movies'); + } +} diff --git a/database/migrations/2022_07_10_153614_create_episodes_table.php b/database/migrations/2022_07_10_153614_create_episodes_table.php new file mode 100644 index 0000000..55ab71f --- /dev/null +++ b/database/migrations/2022_07_10_153614_create_episodes_table.php @@ -0,0 +1,44 @@ +bigIncrements('id'); + + $table->unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->string('server'); + $table->string('name'); + $table->string('slug'); + $table->string('type'); + $table->string('link')->nullable(); + $table->boolean('has_report')->default(false); + $table->string('report_message', 512)->nullable(); + $table->timestamps(); + + $table->index(['movie_id', 'slug']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('episodes'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_actor_movie_table.php b/database/migrations/2022_07_11_062342_create_actor_movie_table.php new file mode 100644 index 0000000..f0329b9 --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_actor_movie_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('actor_id')->index(); + $table->foreign('actor_id')->references('id')->on('actors')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('actor_movie'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_category_movie_table.php b/database/migrations/2022_07_11_062342_create_category_movie_table.php new file mode 100644 index 0000000..64fbafd --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_category_movie_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('category_id')->index(); + $table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('category_movie'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_director_movie_table.php b/database/migrations/2022_07_11_062342_create_director_movie_table.php new file mode 100644 index 0000000..7a2599e --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_director_movie_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('director_id')->index(); + $table->foreign('director_id')->references('id')->on('directors')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('director_movie'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_movie_region_table.php b/database/migrations/2022_07_11_062342_create_movie_region_table.php new file mode 100644 index 0000000..3e82fcd --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_movie_region_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('region_id')->index(); + $table->foreign('region_id')->references('id')->on('regions')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('movie_region'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_movie_studio_table.php b/database/migrations/2022_07_11_062342_create_movie_studio_table.php new file mode 100644 index 0000000..b8e2bf9 --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_movie_studio_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('studio_id')->index(); + $table->foreign('studio_id')->references('id')->on('studios')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('movie_studio'); + } +} diff --git a/database/migrations/2022_07_11_062342_create_movie_tag_table.php b/database/migrations/2022_07_11_062342_create_movie_tag_table.php new file mode 100644 index 0000000..da21c85 --- /dev/null +++ b/database/migrations/2022_07_11_062342_create_movie_tag_table.php @@ -0,0 +1,34 @@ +unsignedBigInteger('movie_id')->index(); + $table->foreign('movie_id')->references('id')->on('movies')->onDelete('cascade'); + + $table->unsignedBigInteger('tag_id')->index(); + $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('movie_tag'); + } +} diff --git a/database/migrations/2022_11_02_071552_create_catalogs_table.php b/database/migrations/2022_11_02_071552_create_catalogs_table.php new file mode 100644 index 0000000..339965c --- /dev/null +++ b/database/migrations/2022_11_02_071552_create_catalogs_table.php @@ -0,0 +1,38 @@ +id(); + $table->string('name')->unique(); + $table->string('slug')->unique()->index(); + $table->integer('paginate')->default(20); + $table->string('value')->nullable(); + $table->string('seo_title')->nullable(); + $table->string('seo_des')->nullable(); + $table->string('seo_key')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('catalogs'); + } +} diff --git a/database/migrations/2023_06_06_185118_add_fulltext_index_to_movies.php b/database/migrations/2023_06_06_185118_add_fulltext_index_to_movies.php new file mode 100644 index 0000000..671f03e --- /dev/null +++ b/database/migrations/2023_06_06_185118_add_fulltext_index_to_movies.php @@ -0,0 +1,29 @@ + 'Phim mới', + 'slug' => 'phim-moi', + 'paginate' => 20, + 'value' => '|is_copyright|0|updated_at|desc', + 'seo_title' => 'Title Phim mới', + 'seo_des' => 'Des Phim mới', + 'seo_key' => 'Key Phim mới', + ], + [ + 'name' => 'Phim bộ', + 'slug' => 'phim-bo', + 'paginate' => 20, + 'value' => '|type|series|updated_at|desc', + 'seo_title' => 'Title Phim bộ', + 'seo_des' => 'Des Phim bộ', + 'seo_key' => 'Key Phim bộ', + ], + [ + 'name' => 'Phim lẻ', + 'slug' => 'phim-le', + 'paginate' => 20, + 'value' => '|type|single|updated_at|desc', + 'seo_title' => 'Title Phim lẻ', + 'seo_des' => 'Des Phim lẻ', + 'seo_key' => 'Key Phim lẻ', + ] + ]; + + foreach ($catalogs as $index => $catalog) { + $result = Catalog::firstOrCreate(collect($catalog)->only('slug')->toArray(), collect($catalog)->except('slug')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + } +} diff --git a/database/seeders/CategoriesTableSeeder.php b/database/seeders/CategoriesTableSeeder.php new file mode 100644 index 0000000..1a52225 --- /dev/null +++ b/database/seeders/CategoriesTableSeeder.php @@ -0,0 +1,121 @@ + "Hành Động", + "slug" => "hanh-dong", + ], + [ + "name" => "Tình Cảm", + "slug" => "tinh-cam", + ], + [ + "name" => "Hài Hước", + "slug" => "hai-huoc", + ], + [ + "name" => "Cổ Trang", + "slug" => "co-trang", + ], + [ + "name" => "Tâm Lý", + "slug" => "tam-ly", + ], + [ + "name" => "Hình Sự", + "slug" => "hinh-su", + ], + [ + "name" => "Chiến Tranh", + "slug" => "chien-tranh", + ], + [ + "name" => "Thể Thao", + "slug" => "the-thao", + ], + [ + "name" => "Võ Thuật", + "slug" => "vo-thuat", + ], + [ + "name" => "Viễn Tưởng", + "slug" => "vien-tuong", + ], + [ + "name" => "Phiêu Lưu", + "slug" => "phieu-luu", + ], + [ + "name" => "Khoa Học", + "slug" => "khoa-hoc", + ], + [ + "name" => "Kinh Dị", + "slug" => "kinh-di", + ], + [ + "name" => "Âm Nhạc", + "slug" => "am-nhac", + ], + [ + "name" => "Thần Thoại", + "slug" => "than-thoai", + ], + [ + "name" => "Tài Liệu", + "slug" => "tai-lieu", + ], + [ + "name" => "Gia Đình", + "slug" => "gia-dinh", + ], + [ + "name" => "Chính kịch", + "slug" => "chinh-kich", + ], + [ + "name" => "Bí ẩn", + "slug" => "bi-an", + ], + [ + "name" => "Học Đường", + "slug" => "hoc-duong", + ], + [ + "name" => "Kinh Điển", + "slug" => "kinh-dien", + ], + [ + "name" => "Phim 18+", + "slug" => "phim-18", + ], + ]; + + foreach ($categories as $index => $category) { + $result = Category::updateOrCreate($category); + + if (!$result) { + $this->command->info("Insert failed at record $index."); + + return; + } + } + + $this->command->info('Inserted ' . count($categories) . ' categories.'); + } +} diff --git a/database/seeders/MenusTableSeeder.php b/database/seeders/MenusTableSeeder.php new file mode 100644 index 0000000..601170b --- /dev/null +++ b/database/seeders/MenusTableSeeder.php @@ -0,0 +1,48 @@ + 'Trang chủ', 'link' => '/', 'type' => 'internal_link']); + $categoryGroup = Menu::firstOrCreate(['name' => 'Thể loại', 'link' => '#', 'type' => 'internal_link']); + $categories = Category::all(); + foreach ($categories as $category) { + Menu::updateOrCreate([ + 'name' => $category->name, + ], [ + 'link' => $category->getUrl(false), + 'type' => 'internal_link', + 'parent_id' => $categoryGroup->id + ]); + } + + $regionGroup = Menu::firstOrCreate(['name' => 'Quốc gia', 'link' => '#', 'type' => 'internal_link']); + $regions = Region::all(); + foreach ($regions as $region) { + Menu::updateOrCreate([ + 'name' => $region->name, + ], [ + 'link' => $region->getUrl(false), + 'type' => 'internal_link', + 'parent_id' => $regionGroup->id + ]); + } + } +} diff --git a/database/seeders/PermissionsSeeder.php b/database/seeders/PermissionsSeeder.php new file mode 100644 index 0000000..834eeae --- /dev/null +++ b/database/seeders/PermissionsSeeder.php @@ -0,0 +1,98 @@ + "Admin", 'guard_name' => 'backpack']); + foreach ($permissions as $index => $permission) { + $result = Permission::firstOrCreate([ + 'name' => $permission, + 'guard_name' => 'backpack' + ]); + + $admin->givePermissionTo($permission); + + if (!$result) { + $this->command->info("Insert failed at record $index."); + + return; + } + } + } +} diff --git a/database/seeders/RegionsTableSeeder.php b/database/seeders/RegionsTableSeeder.php new file mode 100644 index 0000000..9fd3059 --- /dev/null +++ b/database/seeders/RegionsTableSeeder.php @@ -0,0 +1,174 @@ + "Trung Quốc", + "slug" => "trung-quoc", + ], + [ + "name" => "Hàn Quốc", + "slug" => "han-quoc", + ], + [ + "name" => "Nhật Bản", + "slug" => "nhat-ban", + ], + [ + "name" => "Thái Lan", + "slug" => "thai-lan", + ], + [ + "name" => "Âu Mỹ", + "slug" => "au-my", + ], + [ + "name" => "Đài Loan", + "slug" => "dai-loan", + ], + [ + "name" => "Hồng Kông", + "slug" => "hong-kong", + ], + [ + "name" => "Ấn Độ", + "slug" => "an-do", + ], + [ + "name" => "Anh", + "slug" => "anh", + ], + [ + "name" => "Pháp", + "slug" => "phap", + ], + [ + "name" => "Canada", + "slug" => "canada", + ], + [ + "name" => "Quốc Gia Khác", + "slug" => "quoc-gia-khac", + ], + [ + "name" => "Đức", + "slug" => "duc", + ], + [ + "name" => "Tây Ban Nha", + "slug" => "tay-ban-nha", + ], + [ + "name" => "Thổ Nhĩ Kỳ", + "slug" => "tho-nhi-ky", + ], + [ + "name" => "Hà Lan", + "slug" => "ha-lan", + ], + [ + "name" => "Indonesia", + "slug" => "indonesia", + ], + [ + "name" => "Nga", + "slug" => "nga", + ], + [ + "name" => "Mexico", + "slug" => "mexico", + ], + [ + "name" => "Ba lan", + "slug" => "ba-lan", + ], + [ + "name" => "Úc", + "slug" => "uc", + ], + [ + "name" => "Thụy Điển", + "slug" => "thuy-dien", + ], + [ + "name" => "Malaysia", + "slug" => "malaysia", + ], + [ + "name" => "Brazil", + "slug" => "brazil", + ], + [ + "name" => "Philippines", + "slug" => "philippines", + ], + [ + "name" => "Bồ Đào Nha", + "slug" => "bo-dao-nha", + ], + [ + "name" => "Ý", + "slug" => "y", + ], + [ + "name" => "Đan Mạch", + "slug" => "dan-mach", + ], + [ + "name" => "UAE", + "slug" => "uae", + ], + [ + "name" => "Na Uy", + "slug" => "na-uy", + ], + [ + "name" => "Thụy Sĩ", + "slug" => "thuy-si", + ], + [ + "name" => "Châu Phi", + "slug" => "chau-phi", + ], + [ + "name" => "Nam Phi", + "slug" => "nam-phi", + ], + [ + "name" => "Ukraina", + "slug" => "ukraina", + ], + [ + "name" => "Ả Rập Xê Út", + "slug" => "a-rap-xe-ut", + ], + ]; + + foreach ($regions as $index => $region) { + $result = Region::updateOrCreate($region); + + if (!$result) { + $this->command->info("Insert failed at record $index."); + + return; + } + } + + $this->command->info('Inserted ' . count($regions) . ' regions.'); + } +} diff --git a/database/seeders/SettingsTableSeeder.php b/database/seeders/SettingsTableSeeder.php new file mode 100644 index 0000000..91aebfb --- /dev/null +++ b/database/seeders/SettingsTableSeeder.php @@ -0,0 +1,733 @@ + 'site_cache_ttl', + 'name' => 'Thời gian lưu cache', + 'description' => 'site_cache_ttl', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'giây (s)', + ]), + 'value' => 60, + 'active' => 0, + ], + [ + 'key' => 'site_brand', + 'description' => 'site_brand', + 'name' => 'Site Brand', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'textarea', + ]), + 'active' => 0, + ], + [ + 'key' => 'site_logo', + 'description' => 'site_logo', + 'name' => 'Site Logo', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'textarea', + ]), + 'active' => 0, + ], + [ + 'key' => 'site_image_proxy_url', + 'description' => 'site_image_proxy_url', + 'name' => 'Cấu hình proxy', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => '{image_url}: biến hình ảnh' + ]), + 'value' => 'https://images2-focus-opensocial.googleusercontent.com/gadgets/proxy?container=focus&refresh=604800&url={image_url}', + 'active' => 0, + ], + [ + 'key' => 'site_image_proxy_enable', + 'description' => 'site_image_proxy_enable', + 'name' => 'Sử dụng Proxy cho đường dẫn hình ảnh', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'switch', + 'label' => 'Use proxy link in image path', + 'color' => 'primary', // May be any bootstrap color class or an hex color + 'onLabel' => '✓', + 'offLabel' => '✕' + ]), + 'active' => 0, + ] + ]; + + $metas = [ + [ + 'key' => 'site_meta_siteName', + 'description' => 'site_meta_siteName', + 'name' => 'Meta site name', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'tab' => 'General' + ]), + 'value' => 'Vsmov.COM', + 'active' => 0, + ], + [ + 'key' => 'site_meta_shortcut_icon', + 'description' => 'site_meta_shortcut_icon', + 'name' => 'Meta shortcut icon', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'ckfinder', + 'tab' => 'General' + ]), + 'active' => 0, + ], + [ + 'key' => 'site_homepage_title', + 'description' => 'site_homepage_title', + 'name' => 'Tiêu đề mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'tab' => 'General' + ]), + 'value' => 'Phim hay mới cập nhật 2022', + 'active' => 0, + ], + [ + 'key' => 'site_meta_description', + 'description' => 'site_meta_description', + 'name' => 'Meta description', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'textarea', + 'tab' => 'General' + ]), + 'value' => 'Vsmov.COM', + 'active' => 0, + ], + [ + 'key' => 'site_meta_keywords', + 'description' => 'site_meta_keywords', + 'name' => 'Meta keywords', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'textarea', + 'tab' => 'General' + ]), + 'value' => 'Vsmov.COM', + 'active' => 0, + ], + [ + 'key' => 'site_meta_image', + 'description' => 'site_meta_image', + 'name' => 'Meta image', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'ckfinder', + 'tab' => 'General' + ]), + 'active' => 0, + ], + [ + 'key' => 'site_meta_head_tags', + 'description' => 'site_meta_head_tags', + 'name' => 'Head meta tags', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'textarea', + 'tab' => 'General', + 'attributes' => [ + 'rows' => 5 + ], + ]), + 'value' => << + + + + + + + + + + EOT, + 'active' => 0, + ], + [ + 'key' => 'site_movie_title', + 'description' => 'site_movie_title', + 'name' => 'Mẫu tiêu đề trang thông tin phim', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin phim: {name}|{origin_name}|{language}|{quality}|{episode_current}|{publish_year}|...', + 'tab' => 'Phim' + ]), + 'value' => 'Phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_episode_watch_title', + 'description' => 'site_episode_watch_title', + 'name' => 'Mẫu tiêu đề trang xem phim', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin phim: {movie.name}|{movie.origin_name}|{movie.language}|{movie.quality}|{movie.episode_current}|movie.publish_year}|...
Thông tin tập: {name}', + 'tab' => 'Phim' + ]), + 'value' => 'Xem phim {movie.name} tập {name} {movie.language} {movie.quality}', + 'active' => 0, + ], + [ + 'key' => 'site_category_title', + 'description' => 'site_category_title', + 'name' => 'Tiêu đề thể loại mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Thể Loại' + ]), + 'value' => 'Danh sách phim {name} - tổng hợp phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_category_des', + 'description' => 'site_category_des', + 'name' => 'Description thể loại mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Thể Loại' + ]), + 'value' => 'Phim {name} mới nhất tuyển chọn hay nhất. Top những bộ phim {name} đáng để bạn cày 2022', + 'active' => 0, + ], + [ + 'key' => 'site_category_key', + 'description' => 'site_category_key', + 'name' => 'Keywords thể loại mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Thể Loại' + ]), + 'value' => 'Xem phim {name},Phim {name} mới,Phim {name} 2022,phim hay', + 'active' => 0, + ], + [ + 'key' => 'site_region_title', + 'description' => 'site_region_title', + 'name' => 'Tiêu đề quốc gia mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Quốc Gia' + ]), + 'value' => 'Danh sách phim {name} - tổng hợp phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_region_des', + 'description' => 'site_region_des', + 'name' => 'Description quốc gia mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Quốc Gia' + ]), + 'value' => 'Phim {name} mới nhất tuyển chọn hay nhất. Top những bộ phim {name} đáng để bạn cày 2022', + 'active' => 0, + ], + [ + 'key' => 'site_region_key', + 'description' => 'site_region_key', + 'name' => 'Keywords quốc gia mặc định', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Quốc Gia' + ]), + 'value' => 'Xem phim {name},Phim {name} mới,Phim {name} 2022,phim hay', + 'active' => 0, + ], + [ + 'key' => 'site_studio_title', + 'description' => 'site_studio_title', + 'name' => 'Tiêu đề studio', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Studio' + ]), + 'value' => 'Danh sách phim {name} - tổng hợp phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_studio_des', + 'description' => 'site_studio_des', + 'name' => 'Description studio', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Studio' + ]), + 'value' => 'Phim {name} mới nhất tuyển chọn hay nhất. Top những bộ phim {name} đáng để bạn cày 2022', + 'active' => 0, + ], + [ + 'key' => 'site_studio_key', + 'description' => 'site_studio_key', + 'name' => 'Keywords studio', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Studio' + ]), + 'value' => 'Xem phim {name},Phim {name} mới,Phim {name} 2022,phim hay', + 'active' => 0, + ], + [ + 'key' => 'site_actor_title', + 'description' => 'site_actor_title', + 'name' => 'Tiêu đề diễn viên', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Diễn Viên' + ]), + 'value' => 'Phim của diễn viên {name} - tổng hợp phim {name} hay nhất', + 'active' => 0, + ], + [ + 'key' => 'site_actor_des', + 'description' => 'site_actor_des', + 'name' => 'Description diễn viên', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Diễn Viên' + ]), + 'value' => 'Phim của diễn viên {name} - tổng hợp phim {name} hay nhất', + 'active' => 0, + ], + [ + 'key' => 'site_actor_key', + 'description' => 'site_actor_key', + 'name' => 'Keywords diễn viên', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Diễn Viên' + ]), + 'value' => 'xem phim {name},phim {name},tuyen tap phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_director_title', + 'description' => 'site_director_title', + 'name' => 'Tiêu đề đạo diễn', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Đạo Diễn' + ]), + 'value' => 'Phim của đạo diễn {name} - tổng hợp phim {name} hay nhất', + 'active' => 0, + ], + [ + 'key' => 'site_director_des', + 'description' => 'site_director_des', + 'name' => 'Description đạo diễn', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Đạo Diễn' + ]), + 'value' => 'Phim của đạo diễn {name} - tổng hợp phim {name} hay nhất', + 'active' => 0, + ], + [ + 'key' => 'site_director_key', + 'description' => 'site_director_key', + 'name' => 'Keywords đạo diễn', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Đạo Diễn' + ]), + 'value' => 'xem phim {name},phim {name},tuyen tap phim {name}', + 'active' => 0, + ], + [ + 'key' => 'site_tag_title', + 'description' => 'site_tag_title', + 'name' => 'Tiêu đề tag', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Tag' + ]), + 'value' => 'Phim {name} vietsub - phim {name} full hd', + 'active' => 0, + ], + [ + 'key' => 'site_tag_des', + 'description' => 'site_tag_des', + 'name' => 'Description tag', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Tag' + ]), + 'value' => 'Phim {name} vietsub - phim {name} full hd', + 'active' => 0, + ], + [ + 'key' => 'site_tag_key', + 'description' => 'site_tag_key', + 'name' => 'Keywords tag', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => 'Thông tin: {name}', + 'tab' => 'Tag' + ]), + 'value' => 'xem phim {name},phim {name},{name} vietsub', + 'active' => 0, + ], + [ + 'key' => 'site_routes_movie', + 'description' => 'site_routes_movie', + 'name' => 'Trang thông tin phim', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => '{movie}, {id} Buộc phải có ít nhất 1 param', + 'tab' => 'Slug' + ]), + 'value' => '/phim/{movie}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_episode', + 'description' => 'site_routes_episode', + 'name' => 'Trang xem phim', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{movie}, {movie_id} Ít nhất 1
+ {episode}, {id} Bắt buộc
+ EOT, + 'tab' => 'Slug' + ]), + 'value' => '/phim/{movie}/{episode}-{id}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_category', + 'description' => 'site_routes_category', + 'name' => 'Trang thể loại', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{category}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/the-loai/{category}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_region', + 'description' => 'site_routes_region', + 'name' => 'Trang quốc gia', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{region}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/quoc-gia/{region}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_tag', + 'description' => 'site_routes_tag', + 'name' => 'Trang từ khóa', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{tag}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/tu-khoa/{tag}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_types', + 'description' => 'site_routes_types', + 'name' => 'Trang danh sách phim', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{type}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/danh-sach/{type}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_actors', + 'description' => 'site_routes_actors', + 'name' => 'Trang danh diễn viên', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{actor}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/dien-vien/{actor}', + 'active' => 0, + ], + [ + 'key' => 'site_routes_directors', + 'description' => 'site_routes_directors', + 'name' => 'Trang danh đạo diễn', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + 'hint' => <<{director}, {id} Ít nhất 1 + EOT, + 'tab' => 'Slug' + ]), + 'value' => '/dao-dien/{director}', + 'active' => 0, + ], + ]; + + $players = [ + [ + 'key' => 'jwplayer_license', + 'description' => 'jwplayer_license', + 'name' => 'Jwplayer license', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + ]), + 'value' => 'ITWMv7t88JGzI0xPwW8I0+LveiXX9SWbfdmt0ArUSyc=', + 'active' => 0, + ], + [ + 'key' => 'jwplayer_logo_file', + 'description' => 'jwplayer_logo_file', + 'name' => 'Jwplayer logo image', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'ckfinder', + ]), + 'active' => 0, + ], + [ + 'key' => 'jwplayer_logo_link', + 'description' => 'jwplayer_logo_link', + 'name' => 'Jwplayer logo link', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + ]), + 'active' => 0, + ], + [ + 'key' => 'jwplayer_logo_position', + 'description' => 'jwplayer_logo_position', + 'name' => 'Jwplayer logo position', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'select_from_array', + 'options' => [ + 'top-left' => 'Top left', + 'top-right' => 'Top right', + 'bottom-right' => 'Bottom right', + 'bottom-left' => 'Bottom left', + 'control-bar' => 'Control bar', + ] + ]), + 'active' => 0, + ], + [ + 'key' => 'jwplayer_advertising_file', + 'description' => 'jwplayer_advertising_file', + 'name' => 'Jwplayer advertising vast file', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'ckfinder', + ]), + 'active' => 0, + ], + [ + 'key' => 'jwplayer_advertising_skipoffset', + 'description' => 'jwplayer_advertising_skipoffset', + 'name' => 'Jwplayer advertising skipoffset', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'number', + 'hint' => 'giây' + ]), + 'value' => 5, + 'active' => 0, + ], + ]; + + $systems = [ + [ + 'key' => 'site_theme', + 'name' => 'Theme', + 'description' => 'site_theme', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'view', + 'view' => 'themes::selector' + ]), + 'value' => 'default', + 'active' => 0, + ], + ]; + + $others = [ + [ + 'key' => 'social_facebook_app_id', + 'description' => 'social_facebook_app_id', + 'name' => 'Facebook App ID', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'text', + ]), + 'active' => 0, + ], + [ + 'key' => 'site_scripts_facebook_sdk', + 'description' => 'site_scripts_facebook_sdk', + 'name' => 'Facebook JS SDK script tag', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'code', + ]), + 'active' => 0, + ], + [ + 'key' => 'site_scripts_google_analytics', + 'description' => 'site_scripts_google_analytics', + 'name' => 'Google analytics script tag', + 'field' => json_encode([ + 'name' => 'value', + 'type' => 'code', + ]), + 'active' => 0, + ], + ]; + + foreach ($systems as $index => $setting) { + $result = Setting::firstOrCreate(collect($setting)->only('key')->toArray(), collect($setting)->except('key')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + foreach ($generals as $index => $setting) { + $result = Setting::firstOrCreate(collect($setting)->only('key')->toArray(), collect($setting) + ->merge(['group' => 'generals'])->except('key')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + foreach ($metas as $index => $setting) { + $result = Setting::firstOrCreate(collect($setting)->only('key')->toArray(), collect($setting)->merge(['group' => 'metas'])->except('key')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + foreach ($players as $index => $setting) { + $result = Setting::firstOrCreate(collect($setting)->only('key')->toArray(), collect($setting)->merge(['group' => 'jwplayer'])->except('key')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + foreach ($others as $index => $setting) { + $result = Setting::firstOrCreate(collect($setting)->only('key')->toArray(), collect($setting)->merge(['group' => 'others'])->except('key')->toArray()); + + if (!$result) { + $this->command->info("Insert failed at record $index"); + + return; + } + } + + // Delete key not using + $all_settings = array_merge($generals, $metas, $players, $systems, $others); + $all_settings = array_map( function( $a ) { return $a['key']; }, $all_settings ); + Setting::whereIn('group', ['generals', 'metas', 'players', 'systems', 'others'])->whereNotIn('key', $all_settings)->delete(); + } +} diff --git a/draft.yml b/draft.yml new file mode 100644 index 0000000..d380c1f --- /dev/null +++ b/draft.yml @@ -0,0 +1,3 @@ +php artisan make:migration:schema create_categories_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" +php artisan make:migration:schema create_countries_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" +php artisan make:migration:schema create_movies_table --schema="name:string:unique,slug:string:unique,seo_title:string,seo_des:string,seo_key:string" diff --git a/package.json b/package.json new file mode 100644 index 0000000..00c6506 --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "private": true, + "scripts": { + "dev": "npm run development", + "development": "mix", + "watch": "mix watch", + "watch-poll": "mix watch -- --watch-options-poll=1000", + "hot": "mix watch --hot", + "prod": "npm run production", + "production": "mix --production" + }, + "devDependencies": { + "axios": "^0.21", + "laravel-mix": "^6.0.6", + "lodash": "^4.17.19", + "postcss": "^8.1.14" + } +} diff --git a/resources/assets/js/hls.min.js b/resources/assets/js/hls.min.js new file mode 100644 index 0000000..0e18949 --- /dev/null +++ b/resources/assets/js/hls.min.js @@ -0,0 +1,2 @@ +"undefined"!=typeof window&&function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Hls=t():e.Hls=t()}(this,(function(){return function(e){var t={};function r(i){if(t[i])return t[i].exports;var a=t[i]={i:i,l:!1,exports:{}};return e[i].call(a.exports,a,a.exports,r),a.l=!0,a.exports}return r.m=e,r.c=t,r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(r.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)r.d(i,a,function(t){return e[t]}.bind(null,a));return i},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/dist/",r(r.s=13)}([function(e,t,r){"use strict";r.d(t,"a",(function(){return d})),r.d(t,"b",(function(){return c}));var i=r(5);function a(){}var n={trace:a,debug:a,log:a,warn:a,info:a,error:a},s=n;function o(e,t){return t="["+e+"] > "+t}var l=Object(i.a)();function u(e){var t=l.console[e];return t?function(){for(var r=arguments.length,i=new Array(r),a=0;a1?t-1:0),i=1;i0)return t.subarray(i,i+a)},e._readSize=function(e,t){var r=0;return r=(127&e[t])<<21,r|=(127&e[t+1])<<14,r|=(127&e[t+2])<<7,r|=127&e[t+3]},e.getTimeStamp=function(t){for(var r=e.getID3Frames(t),i=0;i>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:d+=String.fromCharCode(n);break;case 12:case 13:o=e[c++],d+=String.fromCharCode((31&n)<<6|63&o);break;case 14:o=e[c++],l=e[c++],d+=String.fromCharCode((15&n)<<12|(63&o)<<6|(63&l)<<0)}}return d},e}();function s(){var e=Object(a.a)();return i||void 0===e.TextDecoder||(i=new e.TextDecoder("utf-8")),i}var o=n._utf8ArrayToStr;t.a=n},function(e,t,r){"use strict";function i(){return"undefined"==typeof window?self:window}r.d(t,"a",(function(){return i}))},function(e,t,r){var i,a,n,s,o;i=/^((?:[a-zA-Z0-9+\-.]+:)?)(\/\/[^\/?#]*)?((?:[^\/?#]*\/)*[^;?#]*)?(;[^?#]*)?(\?[^#]*)?(#.*)?$/,a=/^([^\/?#]*)(.*)$/,n=/(?:\/|^)\.(?=\/)/g,s=/(?:\/|^)\.\.\/(?!\.\.\/)[^\/]*(?=\/)/g,o={buildAbsoluteURL:function(e,t,r){if(r=r||{},e=e.trim(),!(t=t.trim())){if(!r.alwaysNormalize)return e;var i=o.parseURL(e);if(!i)throw new Error("Error trying to parse base URL.");return i.path=o.normalizePath(i.path),o.buildURLFromParts(i)}var n=o.parseURL(t);if(!n)throw new Error("Error trying to parse relative URL.");if(n.scheme)return r.alwaysNormalize?(n.path=o.normalizePath(n.path),o.buildURLFromParts(n)):t;var s=o.parseURL(e);if(!s)throw new Error("Error trying to parse base URL.");if(!s.netLoc&&s.path&&"/"!==s.path[0]){var l=a.exec(s.path);s.netLoc=l[1],s.path=l[2]}s.netLoc&&!s.path&&(s.path="/");var u={scheme:s.scheme,netLoc:n.netLoc,path:null,params:n.params,query:n.query,fragment:n.fragment};if(!n.netLoc&&(u.netLoc=s.netLoc,"/"!==n.path[0]))if(n.path){var d=s.path,c=d.substring(0,d.lastIndexOf("/")+1)+n.path;u.path=o.normalizePath(c)}else u.path=s.path,n.params||(u.params=s.params,n.query||(u.query=s.query));return null===u.path&&(u.path=r.alwaysNormalize?o.normalizePath(n.path):n.path),o.buildURLFromParts(u)},parseURL:function(e){var t=i.exec(e);return t?{scheme:t[1]||"",netLoc:t[2]||"",path:t[3]||"",params:t[4]||"",query:t[5]||"",fragment:t[6]||""}:null},normalizePath:function(e){for(e=e.split("").reverse().join("").replace(n,"");e.length!==(e=e.replace(s,"")).length;);return e.split("").reverse().join("")},buildURLFromParts:function(e){return e.scheme+e.netLoc+e.path+e.params+e.query+e.fragment}},e.exports=o},function(e,t,r){"use strict";var i=function(){function e(e,t){this.subtle=e,this.aesIV=t}return e.prototype.decrypt=function(e,t){return this.subtle.decrypt({name:"AES-CBC",iv:this.aesIV},t,e)},e}(),a=function(){function e(e,t){this.subtle=e,this.key=t}return e.prototype.expandKey=function(){return this.subtle.importKey("raw",this.key,{name:"AES-CBC"},!1,["encrypt","decrypt"])},e}();var n=function(){function e(){this.rcon=[0,1,2,4,8,16,32,64,128,27,54],this.subMix=[new Uint32Array(256),new Uint32Array(256),new Uint32Array(256),new Uint32Array(256)],this.invSubMix=[new Uint32Array(256),new Uint32Array(256),new Uint32Array(256),new Uint32Array(256)],this.sBox=new Uint32Array(256),this.invSBox=new Uint32Array(256),this.key=new Uint32Array(0),this.initTable()}var t=e.prototype;return t.uint8ArrayToUint32Array_=function(e){for(var t=new DataView(e),r=new Uint32Array(4),i=0;i<4;i++)r[i]=t.getUint32(4*i);return r},t.initTable=function(){var e=this.sBox,t=this.invSBox,r=this.subMix,i=r[0],a=r[1],n=r[2],s=r[3],o=this.invSubMix,l=o[0],u=o[1],d=o[2],c=o[3],h=new Uint32Array(256),f=0,g=0,p=0;for(p=0;p<256;p++)h[p]=p<128?p<<1:p<<1^283;for(p=0;p<256;p++){var v=g^g<<1^g<<2^g<<3^g<<4;v=v>>>8^255&v^99,e[f]=v,t[v]=f;var m=h[f],y=h[m],b=h[y],T=257*h[v]^16843008*v;i[f]=T<<24|T>>>8,a[f]=T<<16|T>>>16,n[f]=T<<8|T>>>24,s[f]=T,T=16843009*b^65537*y^257*m^16843008*f,l[v]=T<<24|T>>>8,u[v]=T<<16|T>>>16,d[v]=T<<8|T>>>24,c[v]=T,f?(f=m^h[h[h[b^m]]],g^=h[h[g]]):f=g=1}},t.expandKey=function(e){for(var t=this.uint8ArrayToUint32Array_(e),r=!0,i=0;i>>5}function h(e,t){return!!(t+1=e.length)return!1;var i=c(e,t);if(i<=r)return!1;var a=t+i;if(a===e.length||a+1>>6),!((l=(60&t[r+2])>>>2)>g.length-1))return d=(1&t[r+2])<<2,d|=(192&t[r+3])>>>6,o.b.log("manifest codec:"+n+",ADTS data:type:"+s+",sampleingIndex:"+l+"["+g[l]+"Hz],channelConfig:"+d),/firefox/i.test(h)?l>=6?(s=5,c=new Array(4),u=l-3):(s=2,c=new Array(2),u=l):-1!==h.indexOf("android")?(s=2,c=new Array(2),u=l):(s=5,c=new Array(4),n&&(-1!==n.indexOf("mp4a.40.29")||-1!==n.indexOf("mp4a.40.5"))||!n&&l>=6?u=l-3:((n&&-1!==n.indexOf("mp4a.40.2")&&(l>=6&&1===d||/vivaldi/i.test(h))||!n&&1===d)&&(s=2,c=new Array(2)),u=l)),c[0]=s<<3,c[0]|=(14&l)>>1,c[1]|=(1&l)<<7,c[1]|=d<<3,5===s&&(c[1]|=(14&u)>>1,c[2]=(1&u)<<7,c[2]|=8,c[3]=0),{config:c,samplerate:g[l],channelCount:d,codec:"mp4a.40."+s,manifestCodec:f};e.trigger(i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!0,reason:"invalid ADTS sampling index:"+l})}(t,r,n,s);e.config=l.config,e.samplerate=l.samplerate,e.channelCount=l.channelCount,e.codec=l.codec,e.manifestCodec=l.manifestCodec,o.b.log("parsed codec:"+e.codec+",rate:"+l.samplerate+",nb channel:"+l.channelCount)}}function p(e){return 9216e4/e}function v(e,t,r,i,a){var n=function(e,t,r,i,a){var n,s,o=e.length;if(n=d(e,t),s=c(e,t),(s-=n)>0&&t+n+s<=o)return{headerLength:n,frameLength:s,stamp:r+i*a}}(t,r,i,a,p(e.samplerate));if(n){var s=n.stamp,o=n.headerLength,l=n.frameLength,u={unit:t.subarray(r+o,r+o+l),pts:s,dts:s};return e.samples.push(u),{sample:u,length:l+o}}}var m=r(4),y=function(){function e(e,t,r){this.observer=e,this.config=r,this.remuxer=t}var t=e.prototype;return t.resetInitSegment=function(e,t,r,i){this._audioTrack={container:"audio/adts",type:"audio",id:0,sequenceNumber:0,isAAC:!0,samples:[],len:0,manifestCodec:t,duration:i,inputTimeScale:9e4}},t.resetTimeStamp=function(){},e.probe=function(e){if(!e)return!1;for(var t=(m.a.getID3Data(e,0)||[]).length,r=e.length;tt.length)){var n=this.parseHeader(t,r);if(n&&r+n.frameLength<=t.length){var s=i+a*(9e4*n.samplesPerFrame/n.sampleRate),o={unit:t.subarray(r,r+n.frameLength),pts:s,dts:s};return e.config=[],e.channelCount=n.channelCount,e.samplerate=n.sampleRate,e.samples.push(o),{sample:o,length:n.frameLength}}}},parseHeader:function(e,t){var r=e[t+1]>>3&3,i=e[t+1]>>1&3,a=e[t+2]>>4&15,n=e[t+2]>>2&3,s=e[t+2]>>1&1;if(1!==r&&0!==a&&15!==a&&3!==n){var o=3===r?3-i:3===i?3:4,l=1e3*T.BitratesMap[14*o+a-1],u=3===r?0:2===r?1:2,d=T.SamplingRateMap[3*u+n],c=e[t+3]>>6==3?1:2,h=T.SamplesCoefficients[r][i],f=T.BytesInSlot[i],g=8*h*f;return{sampleRate:d,channelCount:c,frameLength:parseInt(h*l/d+s,10)*f,samplesPerFrame:g}}},isHeaderPattern:function(e,t){return 255===e[t]&&224==(224&e[t+1])&&0!=(6&e[t+1])},isHeader:function(e,t){return!!(t+1e?(this.word<<=e,this.bitsAvailable-=e):(e-=this.bitsAvailable,e-=(t=e>>3)>>3,this.bytesAvailable-=t,this.loadWord(),this.word<<=e,this.bitsAvailable-=e)},t.readBits=function(e){var t=Math.min(this.bitsAvailable,e),r=this.word>>>32-t;return e>32&&o.b.error("Cannot read more than 32 bits at a time"),this.bitsAvailable-=t,this.bitsAvailable>0?this.word<<=t:this.bytesAvailable>0&&this.loadWord(),(t=e-t)>0&&this.bitsAvailable?r<>>e))return this.word<<=e,this.bitsAvailable-=e,e;return this.loadWord(),e+this.skipLZ()},t.skipUEG=function(){this.skipBits(1+this.skipLZ())},t.skipEG=function(){this.skipBits(1+this.skipLZ())},t.readUEG=function(){var e=this.skipLZ();return this.readBits(e+1)-1},t.readEG=function(){var e=this.readUEG();return 1&e?1+e>>>1:-1*(e>>>1)},t.readBoolean=function(){return 1===this.readBits(1)},t.readUByte=function(){return this.readBits(8)},t.readUShort=function(){return this.readBits(16)},t.readUInt=function(){return this.readBits(32)},t.skipScalingList=function(e){var t,r=8,i=8;for(t=0;t=e.length)return void r();if(!(e[t].unit.length<32)){var i=this.decrypter.isSync();if(this.decryptAacSample(e,t,r,i),!i)return}}},t.getAvcEncryptedData=function(e){for(var t=16*Math.floor((e.length-48)/160)+16,r=new Int8Array(t),i=0,a=32;a<=e.length-16;a+=160,i+=16)r.set(e.subarray(a,a+16),i);return r},t.getAvcDecryptedUnit=function(e,t){t=new Uint8Array(t);for(var r=0,i=32;i<=e.length-16;i+=160,r+=16)e.set(t.subarray(r,r+16),i);return e},t.decryptAvcSample=function(e,t,r,i,a,n){var s=this.discardEPB(a.data),o=this.getAvcEncryptedData(s),l=this;this.decryptBuffer(o.buffer,(function(o){a.data=l.getAvcDecryptedUnit(s,o),n||l.decryptAvcSamples(e,t,r+1,i)}))},t.decryptAvcSamples=function(e,t,r,i){for(;;t++,r=0){if(t>=e.length)return void i();for(var a=e[t].units;!(r>=a.length);r++){var n=a[r];if(!(n.length<=48||1!==n.type&&5!==n.type)){var s=this.decrypter.isSync();if(this.decryptAvcSample(e,t,r,i,n,s),!s)return}}}},e}(),R={video:1,audio:2,id3:3,text:4},A=function(){function e(e,t,r,i){this.observer=e,this.config=r,this.typeSupported=i,this.remuxer=t,this.sampleAes=null,this.pmtUnknownTypes={}}var t=e.prototype;return t.setDecryptData=function(e){null!=e&&null!=e.key&&"SAMPLE-AES"===e.method?this.sampleAes=new _(this.observer,this.config,e,this.discardEPB):this.sampleAes=null},e.probe=function(t){var r=e._syncOffset(t);return!(r<0)&&(r&&o.b.warn("MPEG2-TS detected but first sync word found @ offset "+r+", junk ahead ?"),!0)},e._syncOffset=function(e){for(var t=Math.min(1e3,e.length-564),r=0;r>4>1){if((c=l+5+t[l+4])===l+188)continue}else c=l+4;switch(d){case b:u&&(_&&(h=L(_))&&D(h,!1),_={data:[],size:0}),_&&(_.data.push(t.subarray(c,l+188)),_.size+=l+188-c);break;case T:u&&(R&&(h=L(R))&&(m.isAAC?O(h):C(h)),R={data:[],size:0}),R&&(R.data.push(t.subarray(c,l+188)),R.size+=l+188-c);break;case E:u&&(A&&(h=L(A))&&I(h),A={data:[],size:0}),A&&(A.data.push(t.subarray(c,l+188)),A.size+=l+188-c);break;case 0:u&&(c+=t[c]+1),S=this._pmtId=k(t,c);break;case S:u&&(c+=t[c]+1);var x=w(t,c,!0===this.typeSupported.mpeg||!0===this.typeSupported.mp3,null!=this.sampleAes);(b=x.avc)>0&&(v.pid=b),(T=x.audio)>0&&(m.pid=T,m.isAAC=x.isAAC),(E=x.id3)>0&&(y.pid=E),g&&!p&&(o.b.log("reparse from beginning"),g=!1,l=P-188),p=this.pmtParsed=!0;break;case 17:case 8191:break;default:g=!0}}else this.observer.trigger(i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!1,reason:"TS packet did not start with 0x47"});_&&(h=L(_))?(D(h,!0),v.pesData=null):v.pesData=_,R&&(h=L(R))?(m.isAAC?O(h):C(h),m.pesData=null):(R&&R.size&&o.b.log("last AAC PES packet truncated,might overlap between fragments"),m.pesData=R),A&&(h=L(A))?(I(h),y.pesData=null):y.pesData=A,null==this.sampleAes?this.remuxer.remux(m,v,y,this._txtTrack,r,n,s):this.decryptAndRemux(m,v,y,this._txtTrack,r,n,s)},t.decryptAndRemux=function(e,t,r,i,a,n,s){if(e.samples&&e.isAAC){var o=this;this.sampleAes.decryptAacSamples(e.samples,0,(function(){o.decryptAndRemuxAvc(e,t,r,i,a,n,s)}))}else this.decryptAndRemuxAvc(e,t,r,i,a,n,s)},t.decryptAndRemuxAvc=function(e,t,r,i,a,n,s){if(t.samples){var o=this;this.sampleAes.decryptAvcSamples(t.samples,0,0,(function(){o.remuxer.remux(e,t,r,i,a,n,s)}))}else this.remuxer.remux(e,t,r,i,a,n,s)},t.destroy=function(){this._initPTS=this._initDTS=void 0,this._duration=0},t._parsePAT=function(e,t){return(31&e[t+10])<<8|e[t+11]},t._trackUnknownPmt=function(e,t,r){var i=this.pmtUnknownTypes[e]||0;return 0===i&&(this.pmtUnknownTypes[e]=0,t.call(o.b,r)),this.pmtUnknownTypes[e]++,i},t._parsePMT=function(e,t,r,i){var a,n,s={audio:-1,avc:-1,id3:-1,isAAC:!0};for(a=t+3+((15&e[t+1])<<8|e[t+2])-4,t+=12+((15&e[t+10])<<8|e[t+11]);t1;){var h=new Uint8Array(c[0].length+c[1].length);h.set(c[0]),h.set(c[1],c[0].length),c[0]=h,c.splice(1,1)}if(1===((t=c[0])[0]<<16)+(t[1]<<8)+t[2]){if((i=(t[4]<<8)+t[5])&&i>e.size-6)return null;if(192&(r=t[7])&&((s=536870912*(14&t[9])+4194304*(255&t[10])+16384*(254&t[11])+128*(255&t[12])+(254&t[13])/2)>4294967295&&(s-=8589934592),64&r?((l=536870912*(14&t[14])+4194304*(255&t[15])+16384*(254&t[16])+128*(255&t[17])+(254&t[18])/2)>4294967295&&(l-=8589934592),s-l>54e5&&(o.b.warn(Math.round((s-l)/9e4)+"s delta between PTS and DTS, align them"),s=l)):l=s),u=(a=t[8])+9,e.size<=u)return null;e.size-=u,n=new Uint8Array(e.size);for(var f=0,g=c.length;fp){u-=p;continue}t=t.subarray(u),p-=u,u=0}n.set(t,d),d+=p}return i&&(i-=a+3),{data:n,pts:s,dts:l,len:i}}return null},t.pushAccesUnit=function(e,t){if(e.units.length&&e.frame){var r=t.samples,i=r.length;if(isNaN(e.pts)){if(!i)return void t.dropped++;var a=r[i-1];e.pts=a.pts,e.dts=a.dts}!this.config.forceKeyFrameOnDiscontinuity||!0===e.key||t.sps&&(i||this.contiguous)?(e.id=i,r.push(e)):t.dropped++}e.debug.length&&o.b.log(e.pts+"/"+e.dts+":"+e.debug)},t._parseAVCPES=function(e,t){var r,i,a,n=this,s=this._avcTrack,o=this._parseAVCNALu(e.data),l=this.avcSample,u=!1,d=this.pushAccesUnit.bind(this),c=function(e,t,r,i){return{key:e,pts:t,dts:r,units:[],debug:i}};e.data=null,l&&o.length&&!s.audFound&&(d(l,s),l=this.avcSample=c(!1,e.pts,e.dts,"")),o.forEach((function(t){switch(t.type){case 1:i=!0,l||(l=n.avcSample=c(!0,e.pts,e.dts,"")),l.frame=!0;var o=t.data;if(u&&o.length>4){var h=new S(o).readSliceType();2!==h&&4!==h&&7!==h&&9!==h||(l.key=!0)}break;case 5:i=!0,l||(l=n.avcSample=c(!0,e.pts,e.dts,"")),l.key=!0,l.frame=!0;break;case 6:i=!0,(r=new S(n.discardEPB(t.data))).readUByte();for(var f=0,g=0,p=!1,v=0;!p&&r.bytesAvailable>1;){f=0;do{f+=v=r.readUByte()}while(255===v);g=0;do{g+=v=r.readUByte()}while(255===v);if(4===f&&0!==r.bytesAvailable){if(p=!0,181===r.readUByte())if(49===r.readUShort())if(1195456820===r.readUInt())if(3===r.readUByte()){var y=r.readUByte(),b=31&y,T=[y,r.readUByte()];for(a=0;a16){var E=[];for(a=0;a<16;a++)E.push(r.readUByte().toString(16)),3!==a&&5!==a&&7!==a&&9!==a||E.push("-");var _=g-16,R=new Uint8Array(_);for(a=0;a<_;a++)R[a]=r.readUByte();n._insertSampleInOrder(n._txtTrack.samples,{pts:e.pts,payloadType:f,uuid:E.join(""),userDataBytes:R,userData:Object(m.b)(R.buffer)})}}else if(g0){if(t.pts>=e[r-1].pts)e.push(t);else for(var i=r-1;i>=0;i--)if(t.pts=0)i={data:e.subarray(c,n-l-1),type:a},d.push(i);else{var h=this._getLastNalUnit();if(h&&(u&&n<=4-u&&h.state&&(h.data=h.data.subarray(0,h.data.byteLength-u)),(r=n-l-1)>0)){var f=new Uint8Array(h.data.byteLength+r);f.set(h.data,0),f.set(e.subarray(0,r),h.data.byteLength),h.data=f}}n=0&&l>=0&&(i={data:e.subarray(c,s),type:a,state:l},d.push(i)),0===d.length){var g=this._getLastNalUnit();if(g){var p=new Uint8Array(g.data.byteLength+e.byteLength);p.set(g.data,0),p.set(e,g.data.byteLength),g.data=p}}return o.naluState=l,d},t.discardEPB=function(e){for(var t,r,i=e.byteLength,a=[],n=1;n1&&(o.b.log("AAC: align PTS for overlapping frames by "+Math.round((E-m)/90)),m=E)}for(;n>24&255,t[1]=i>>16&255,t[2]=i>>8&255,t[3]=255&i,t.set(e,4),a=0,i=8;a>24&255,t>>16&255,t>>8&255,255&t,i>>24,i>>16&255,i>>8&255,255&i,a>>24,a>>16&255,a>>8&255,255&a,85,196,0,0]))},e.mdia=function(t){return e.box(e.types.mdia,e.mdhd(t.timescale,t.duration),e.hdlr(t.type),e.minf(t))},e.mfhd=function(t){return e.box(e.types.mfhd,new Uint8Array([0,0,0,0,t>>24,t>>16&255,t>>8&255,255&t]))},e.minf=function(t){return"audio"===t.type?e.box(e.types.minf,e.box(e.types.smhd,e.SMHD),e.DINF,e.stbl(t)):e.box(e.types.minf,e.box(e.types.vmhd,e.VMHD),e.DINF,e.stbl(t))},e.moof=function(t,r,i){return e.box(e.types.moof,e.mfhd(t),e.traf(i,r))},e.moov=function(t){for(var r=t.length,i=[];r--;)i[r]=e.trak(t[r]);return e.box.apply(null,[e.types.moov,e.mvhd(t[0].timescale,t[0].duration)].concat(i).concat(e.mvex(t)))},e.mvex=function(t){for(var r=t.length,i=[];r--;)i[r]=e.trex(t[r]);return e.box.apply(null,[e.types.mvex].concat(i))},e.mvhd=function(t,r){r*=t;var i=Math.floor(r/(L+1)),a=Math.floor(r%(L+1)),n=new Uint8Array([1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,t>>24&255,t>>16&255,t>>8&255,255&t,i>>24,i>>16&255,i>>8&255,255&i,a>>24,a>>16&255,a>>8&255,255&a,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,255]);return e.box(e.types.mvhd,n)},e.sdtp=function(t){var r,i,a=t.samples||[],n=new Uint8Array(4+a.length);for(i=0;i>>8&255),n.push(255&a),n=n.concat(Array.prototype.slice.call(i));for(r=0;r>>8&255),s.push(255&a),s=s.concat(Array.prototype.slice.call(i));var o=e.box(e.types.avcC,new Uint8Array([1,n[3],n[4],n[5],255,224|t.sps.length].concat(n).concat([t.pps.length]).concat(s))),l=t.width,u=t.height,d=t.pixelRatio[0],c=t.pixelRatio[1];return e.box(e.types.avc1,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,l>>8&255,255&l,u>>8&255,255&u,0,72,0,0,0,72,0,0,0,0,0,0,0,1,18,100,97,105,108,121,109,111,116,105,111,110,47,104,108,115,46,106,115,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,17,17]),o,e.box(e.types.btrt,new Uint8Array([0,28,156,128,0,45,198,192,0,45,198,192])),e.box(e.types.pasp,new Uint8Array([d>>24,d>>16&255,d>>8&255,255&d,c>>24,c>>16&255,c>>8&255,255&c])))},e.esds=function(e){var t=e.config.length;return new Uint8Array([0,0,0,0,3,23+t,0,1,0,4,15+t,64,21,0,0,0,0,0,0,0,0,0,0,0,5].concat([t]).concat(e.config).concat([6,1,2]))},e.mp4a=function(t){var r=t.samplerate;return e.box(e.types.mp4a,new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,t.channelCount,0,16,0,0,0,0,r>>8&255,255&r,0,0]),e.box(e.types.esds,e.esds(t)))},e.mp3=function(t){var r=t.samplerate;return e.box(e.types[".mp3"],new Uint8Array([0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,t.channelCount,0,16,0,0,0,0,r>>8&255,255&r,0,0]))},e.stsd=function(t){return"audio"===t.type?t.isAAC||"mp3"!==t.codec?e.box(e.types.stsd,e.STSD,e.mp4a(t)):e.box(e.types.stsd,e.STSD,e.mp3(t)):e.box(e.types.stsd,e.STSD,e.avc1(t))},e.tkhd=function(t){var r=t.id,i=t.duration*t.timescale,a=t.width,n=t.height,s=Math.floor(i/(L+1)),o=Math.floor(i%(L+1));return e.box(e.types.tkhd,new Uint8Array([1,0,0,7,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,3,r>>24&255,r>>16&255,r>>8&255,255&r,0,0,0,0,s>>24,s>>16&255,s>>8&255,255&s,o>>24,o>>16&255,o>>8&255,255&o,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,a>>8&255,255&a,0,0,n>>8&255,255&n,0,0]))},e.traf=function(t,r){var i=e.sdtp(t),a=t.id,n=Math.floor(r/(L+1)),s=Math.floor(r%(L+1));return e.box(e.types.traf,e.box(e.types.tfhd,new Uint8Array([0,0,0,0,a>>24,a>>16&255,a>>8&255,255&a])),e.box(e.types.tfdt,new Uint8Array([1,0,0,0,n>>24,n>>16&255,n>>8&255,255&n,s>>24,s>>16&255,s>>8&255,255&s])),e.trun(t,i.length+16+20+8+16+8+8),i)},e.trak=function(t){return t.duration=t.duration||4294967295,e.box(e.types.trak,e.tkhd(t),e.mdia(t))},e.trex=function(t){var r=t.id;return e.box(e.types.trex,new Uint8Array([0,0,0,0,r>>24,r>>16&255,r>>8&255,255&r,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1]))},e.trun=function(t,r){var i,a,n,s,o,l,u=t.samples||[],d=u.length,c=12+16*d,h=new Uint8Array(c);for(r+=8+c,h.set([0,0,15,1,d>>>24&255,d>>>16&255,d>>>8&255,255&d,r>>>24&255,r>>>16&255,r>>>8&255,255&r],0),i=0;i>>24&255,n>>>16&255,n>>>8&255,255&n,s>>>24&255,s>>>16&255,s>>>8&255,255&s,o.isLeading<<2|o.dependsOn,o.isDependedOn<<6|o.hasRedundancy<<4|o.paddingValue<<1|o.isNonSync,61440&o.degradPrio,15&o.degradPrio,l>>>24&255,l>>>16&255,l>>>8&255,255&l],12+16*i);return e.box(e.types.trun,h)},e.initSegment=function(t){e.types||e.init();var r,i=e.moov(t);return(r=new Uint8Array(e.FTYP.byteLength+i.byteLength)).set(e.FTYP),r.set(i,e.FTYP.byteLength),r},e}();function O(e,t,r,i){void 0===r&&(r=1),void 0===i&&(i=!1);var a=e*t*r;return i?Math.round(a):a}function C(e,t){return void 0===t&&(t=!1),O(e,1e3,1/9e4,t)}function I(e,t){return void 0===t&&(t=1),O(e,9e4,1/t)}var P,x=I(10),M=I(.2),F=function(){function e(e,t,r,i){this.observer=e,this.config=t,this.typeSupported=r;var a=navigator.userAgent;this.isSafari=i&&i.indexOf("Apple")>-1&&a&&!a.match("CriOS"),this.ISGenerated=!1}var t=e.prototype;return t.destroy=function(){},t.resetTimeStamp=function(e){this._initPTS=this._initDTS=e},t.resetInitSegment=function(){this.ISGenerated=!1},t.remux=function(e,t,r,a,n,s,l){if(this.ISGenerated||this.generateIS(e,t,n),this.ISGenerated){var u=e.samples.length,d=t.samples.length,c=n,h=n;if(u&&d){var f=(n>0?e.samples[0].dts-t.samples[0].dts:e.samples[0].pts-t.samples[0].pts)/t.inputTimeScale;c+=Math.max(0,f),h+=Math.max(0,-f)}if(u){e.timescale||(o.b.warn("regenerate InitSegment as audio detected"),this.generateIS(e,t,n));var g,p=this.remuxAudio(e,c,s,l);if(d)p&&(g=p.endPTS-p.startPTS),t.timescale||(o.b.warn("regenerate InitSegment as video detected"),this.generateIS(e,t,n)),this.remuxVideo(t,h,s,g,l)}else if(d){var v=this.remuxVideo(t,h,s,0,l);v&&e.codec&&this.remuxEmptyAudio(e,c,s,v)}}r.samples.length&&this.remuxID3(r,n),a.samples.length&&this.remuxText(a,n),this.observer.trigger(i.a.FRAG_PARSED)},t.generateIS=function(e,t,r){var n,s,l=this.observer,u=e.samples,d=t.samples,c=this.typeSupported,h="audio/mp4",f={},g={tracks:f},p=void 0===this._initPTS;if(p&&(n=s=1/0),e.config&&u.length&&(e.timescale=e.samplerate,o.b.log("audio sampling rate : "+e.samplerate),e.isAAC||(c.mpeg?(h="audio/mpeg",e.codec=""):c.mp3&&(e.codec="mp3")),f.audio={container:h,codec:e.codec,initSegment:!e.isAAC&&c.mpeg?new Uint8Array:D.initSegment([e]),metadata:{channelCount:e.channelCount}},p&&(n=s=u[0].pts-Math.round(e.inputTimeScale*r))),t.sps&&t.pps&&d.length){var v=t.inputTimeScale;if(t.timescale=v,f.video={container:"video/mp4",codec:t.codec,initSegment:D.initSegment([t]),metadata:{width:t.width,height:t.height}},p){var m=Math.round(v*r);n=Math.min(n,d[0].pts-m),s=Math.min(s,d[0].dts-m),this.observer.trigger(i.a.INIT_PTS_FOUND,{initPTS:n})}}else p&&f.audio&&this.observer.trigger(i.a.INIT_PTS_FOUND,{initPTS:n});Object.keys(f).length?(l.trigger(i.a.FRAG_PARSING_INIT_SEGMENT,g),this.ISGenerated=!0,p&&(this._initPTS=n,this._initDTS=s)):l.trigger(i.a.ERROR,{type:a.b.MEDIA_ERROR,details:a.a.FRAG_PARSING_ERROR,fatal:!1,reason:"no audio/video samples found"})},t.remuxVideo=function(e,t,r,n,s){var l,u,d,c,h,f=8,g=Number.POSITIVE_INFINITY,p=Number.NEGATIVE_INFINITY,v=e.timescale,m=e.samples,y=[],b=m.length,T=this._PTSNormalize,E=this._initPTS,S=this.nextAvcDts,_=this.isSafari;if(0!==b){_&&(r|=b&&S&&(s&&Math.abs(t-S/v)<.1||Math.abs(m[0].pts-S-E)k;(L||w<-1)&&(L?o.b.warn("AVC: "+C(w,!0)+"ms ("+w+"dts) hole between fragments detected, filling it"):o.b.warn("AVC: "+C(-w,!0)+"ms ("+w+"dts) overlapping between fragments detected"),c=S,g-=w,m[0].dts=c,m[0].pts=g,o.b.log("Video: First PTS/DTS adjusted: "+C(g,!0)+"/"+C(c,!0)+", delta: "+C(w,!0)+" ms"))}c=Math.max(c,0);for(var O=0,I=0,P=0;P0?j-1:j].dts;if(J.stretchShortVideoTrack){var ee=J.maxBufferHole,te=Math.floor(ee*v),re=(n?g+n*v:this.nextAudioPts)-H.pts;re>te?((l=re-Z)<0&&(l=Z),o.b.log("It is approximately "+C(re,!1)+" ms to the next segment; using duration "+C(l,!1)+" ms for the last video frame.")):l=Z}else l=Z}W=Math.round(H.pts-H.dts)}y.push({size:Y,duration:l,cts:W,flags:{isLeading:0,isDependedOn:0,hasRedundancy:0,degradPrio:0,dependsOn:H.key?2:1,isNonSync:H.key?0:1}})}this.nextAvcDts=h+l;var ie=e.dropped;if(e.nbNalu=0,e.dropped=0,y.length&&navigator.userAgent.toLowerCase().indexOf("chrome")>-1){var ae=y[0].flags;ae.dependsOn=2,ae.isNonSync=0}e.samples=y,d=D.moof(e.sequenceNumber++,c,e),e.samples=[];var ne={data1:d,data2:u,startPTS:g/v,endPTS:(p+l)/v,startDTS:c/v,endDTS:this.nextAvcDts/v,type:"video",hasAudio:!1,hasVideo:!0,nb:y.length,dropped:ie};return this.observer.trigger(i.a.FRAG_PARSING_DATA,ne),ne}},t.remuxAudio=function(e,t,r,n){var s,l,u,d,c,h,f=e.inputTimeScale,g=e.timescale,p=f/g,v=(e.isAAC?1024:1152)*p,m=this._PTSNormalize,y=this._initPTS,b=!e.isAAC&&this.typeSupported.mpeg,T=b?0:8,E=e.samples,S=[],_=this.nextAudioPts;if(r|=E.length&&_&&(n&&Math.abs(t-_/f)<.1||Math.abs(E[0].pts-_-y)<20*v),E.forEach((function(e){e.pts=e.dts=m(e.pts-y,t*f)})),0!==(E=E.filter((function(e){return e.pts>=0}))).length){if(r||(_=n?t*f:E[0].pts),e.isAAC)for(var R=this.config.maxAudioFramesDrift,A=0,k=_;A=R*v&&L0&&V0&&((l=w.getSilentFrame(e.manifestCodec||e.codec,e.channelCount))||(l=j.subarray()),N+=Y*l.length);else if(V<-12){o.b.log("drop overlapping AAC sample, expected/parsed/delta: "+C(_,!0)+" ms / "+C(H,!0)+" ms / "+C(-V,!0)+" ms"),N-=j.byteLength;continue}H=_}if(c=H,!(N>0))return;N+=T;try{u=new Uint8Array(N)}catch(e){return void this.observer.trigger(i.a.ERROR,{type:a.b.MUX_ERROR,details:a.a.REMUX_ALLOC_ERROR,fatal:!1,bytes:N,reason:"fail allocating audio mdat "+N})}b||(new DataView(u.buffer).setUint32(0,N),u.set(D.types.mdat,4));for(var W=0;W=2&&(X=S[U-2].duration,s.duration=X),U){this.nextAudioPts=_=h+p*X,e.samples=S,d=b?new Uint8Array:D.moof(e.sequenceNumber++,c/p,e),e.samples=[];var z=c/f,Q=_/f,$={data1:d,data2:u,startPTS:z,endPTS:Q,startDTS:z,endDTS:Q,type:"audio",hasAudio:!0,hasVideo:!1,nb:U};return this.observer.trigger(i.a.FRAG_PARSING_DATA,$),$}return null}},t.remuxEmptyAudio=function(e,t,r,i){var a=e.inputTimeScale,n=a/(e.samplerate?e.samplerate:a),s=this.nextAudioPts,l=(void 0!==s?s:i.startDTS*a)+this._initDTS,u=i.endDTS*a+this._initDTS,d=1024*n,c=Math.ceil((u-l)/d),h=w.getSilentFrame(e.manifestCodec||e.codec,e.channelCount);if(o.b.warn("remux empty Audio"),h){for(var f=[],g=0;g4294967296;)e+=r;return e},e}(),U=function(){function e(e){this.observer=e}var t=e.prototype;return t.destroy=function(){},t.resetTimeStamp=function(){},t.resetInitSegment=function(){},t.remux=function(e,t,r,a,n,s,o,l){var u=this.observer,d="";e&&(d+="audio"),t&&(d+="video"),u.trigger(i.a.FRAG_PARSING_DATA,{data1:l,startPTS:n,startDTS:n,type:d,hasAudio:!!e,hasVideo:!!t,nb:1,dropped:0}),u.trigger(i.a.FRAG_PARSED)},e}(),N=Object(l.a)();try{P=N.performance.now.bind(N.performance)}catch(e){o.b.debug("Unable to use Performance API on this environment"),P=N.Date.now}var B=function(){function e(e,t,r,i){this.observer=e,this.typeSupported=t,this.config=r,this.vendor=i}var t=e.prototype;return t.destroy=function(){var e=this.demuxer;e&&e.destroy()},t.push=function(e,t,r,a,s,o,l,u,d,c,h,f){var g=this;if(e.byteLength>0&&null!=t&&null!=t.key&&"AES-128"===t.method){var p=this.decrypter;null==p&&(p=this.decrypter=new n.a(this.observer,this.config));var v=P();p.decrypt(e,t.key.buffer,t.iv.buffer,(function(e){var n=P();g.observer.trigger(i.a.FRAG_DECRYPTED,{stats:{tstart:v,tdecrypt:n}}),g.pushDecrypted(new Uint8Array(e),t,new Uint8Array(r),a,s,o,l,u,d,c,h,f)}))}else this.pushDecrypted(new Uint8Array(e),t,new Uint8Array(r),a,s,o,l,u,d,c,h,f)},t.pushDecrypted=function(e,t,r,n,s,o,l,u,d,c,h,f){var g=this.demuxer;if(!g||(l||u)&&!this.probe(e)){for(var p=this.observer,v=this.typeSupported,m=this.config,T=[{demux:A,remux:F},{demux:b.a,remux:U},{demux:y,remux:F},{demux:k,remux:F}],E=0,S=T.length;E0},e.bin2str=function(e){return String.fromCharCode.apply(null,e)},e.readUint16=function(e,t){e.data&&(t+=e.start,e=e.data);var r=e[t]<<8|e[t+1];return r<0?65536+r:r},e.readUint32=function(e,t){e.data&&(t+=e.start,e=e.data);var r=e[t]<<24|e[t+1]<<16|e[t+2]<<8|e[t+3];return r<0?4294967296+r:r},e.writeUint32=function(e,t,r){e.data&&(t+=e.start,e=e.data),e[t]=r>>24,e[t+1]=r>>16&255,e[t+2]=r>>8&255,e[t+3]=255&r},e.findBox=function(t,r){var i,a,n,s,o,l,u=[];if(t.data?(o=t.start,n=t.end,t=t.data):(o=0,n=t.byteLength),!r.length)return null;for(i=o;i1?i+a:n,e.bin2str(t.subarray(i+4,i+8))===r[0]&&(1===r.length?u.push({data:t,start:i+8,end:l}):(s=e.findBox({data:t,start:i+8,end:l},r.slice(1))).length&&(u=u.concat(s))),i=l;return u},e.parseSegmentIndex=function(t){var r,i=e.findBox(t,["moov"])[0],a=i?i.end:null,n=0,s=e.findBox(t,["sidx"]);if(!s||!s[0])return null;r=[];var o=(s=s[0]).data[0];n=0===o?8:16;var l=e.readUint32(s,n);n+=4;n+=0===o?8:16,n+=2;var u=s.end+0,d=e.readUint16(s,n);n+=2;for(var c=0;c>>31)return void console.warn("SIDX has hierarchical references (not supported)");var p=e.readUint32(s,h);h+=4,r.push({referenceSize:g,subsegmentDuration:p,info:{duration:p/l,start:u,end:u+g-1}}),u+=g,n=h+=4}return{earliestPresentationTime:0,timescale:l,version:o,referencesCount:d,references:r,moovEndOffset:a}},e.parseInitSegment=function(t){var r=[];return e.findBox(t,["moov","trak"]).forEach((function(t){var a=e.findBox(t,["tkhd"])[0];if(a){var n=a.data[a.start],s=0===n?12:20,o=e.readUint32(a,s),l=e.findBox(t,["mdia","mdhd"])[0];if(l){s=0===(n=l.data[l.start])?12:20;var u=e.readUint32(l,s),d=e.findBox(t,["mdia","hdlr"])[0];if(d){var c={soun:"audio",vide:"video"}[e.bin2str(d.data.subarray(d.start+8,d.start+12))];if(c){var h=e.findBox(t,["mdia","minf","stbl","stsd"]);if(h.length){h=h[0];var f=e.bin2str(h.data.subarray(h.start+12,h.start+16));i.b.log("MP4Demuxer:"+c+":"+f+" found")}r[o]={timescale:u,type:c},r[c]={timescale:u,id:o}}}}}})),r},e.getStartDTS=function(t,r){var i,a,n;return i=e.findBox(r,["moof","traf"]),a=[].concat.apply([],i.map((function(r){return e.findBox(r,["tfhd"]).map((function(i){var a,n;return a=e.readUint32(i,4),n=t[a].timescale||9e4,e.findBox(r,["tfdt"]).map((function(t){var r,i;return r=t.data[t.start],i=e.readUint32(t,4),1===r&&(i*=Math.pow(2,32),i+=e.readUint32(t,8)),i}))[0]/n}))}))),n=Math.min.apply(null,a),isFinite(n)?n:0},e.offsetStartDTS=function(t,r,i){e.findBox(r,["moof","traf"]).map((function(r){return e.findBox(r,["tfhd"]).map((function(a){var s=e.readUint32(a,4),o=t[s].timescale||9e4;e.findBox(r,["tfdt"]).map((function(t){var r=t.data[t.start],a=e.readUint32(t,4);if(0===r)e.writeUint32(t,4,a-i*o);else{a*=Math.pow(2,32),a+=e.readUint32(t,8),a-=i*o,a=Math.max(a,0);var s=Math.floor(a/(n+1)),l=Math.floor(a%(n+1));e.writeUint32(t,4,s),e.writeUint32(t,8,l)}}))}))}))},t.append=function(t,r,i,n){var s=this.initData;s||(this.resetInitSegment(t,this.audioCodec,this.videoCodec,!1),s=this.initData);var o,l=this.initPTS;if(void 0===l){var u=e.getStartDTS(s,t);this.initPTS=l=u-r,this.observer.trigger(a.a.INIT_PTS_FOUND,{initPTS:l})}e.offsetStartDTS(s,t,l),o=e.getStartDTS(s,t),this.remuxer.remux(s.audio,s.video,null,null,o,i,n,t)},t.destroy=function(){},e}();t.a=s},function(e,t,r){function i(e){var t={};function r(i){if(t[i])return t[i].exports;var a=t[i]={i:i,l:!1,exports:{}};return e[i].call(a.exports,a,a.exports,r),a.l=!0,a.exports}r.m=e,r.c=t,r.i=function(e){return e},r.d=function(e,t,i){r.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},r.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="/",r.oe=function(e){throw console.error(e),e};var i=r(r.s=ENTRY_MODULE);return i.default||i}function a(e){return(e+"").replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}function n(e,t,i){var n={};n[i]=[];var s=t.toString(),o=s.match(/^function\s?\w*\(\w+,\s*\w+,\s*(\w+)\)/);if(!o)return n;for(var l,u=o[1],d=new RegExp("(\\\\n|\\W)"+a(u)+"\\(\\s*(/\\*.*?\\*/)?\\s*.*?([\\.|\\-|\\+|\\w|/|@]+).*?\\)","g");l=d.exec(s);)"dll-reference"!==l[3]&&n[i].push(l[3]);for(d=new RegExp("\\("+a(u)+'\\("(dll-reference\\s([\\.|\\-|\\+|\\w|/|@]+))"\\)\\)\\(\\s*(/\\*.*?\\*/)?\\s*.*?([\\.|\\-|\\+|\\w|/|@]+).*?\\)',"g");l=d.exec(s);)e[l[2]]||(n[i].push(l[1]),e[l[2]]=r(l[1]).m),n[l[2]]=n[l[2]]||[],n[l[2]].push(l[4]);for(var c,h=Object.keys(n),f=0;f0}),!1)}e.exports=function(e,t){t=t||{};var a={main:r.m},o=t.all?{main:Object.keys(a.main)}:function(e,t){for(var r={main:[t]},i={main:[]},a={main:{}};s(r);)for(var o=Object.keys(r),l=0;l1?r-1:0),a=1;a1?r-1:0),a=1;a1?t-1:0),i=1;i>8*(15-r)&255;return t},a.setDecryptDataFromLevelKey=function(e,t){var r=e;return(null==e?void 0:e.method)&&e.uri&&!e.iv&&((r=new v(e.baseuri,e.reluri)).method=e.method,r.iv=this.createInitializationVector(t)),r},t=e,(r=[{key:"url",get:function(){return!this._url&&this.relurl&&(this._url=Object(s.buildAbsoluteURL)(this.baseurl,this.relurl,{alwaysNormalize:!0})),this._url},set:function(e){this._url=e}},{key:"byteRange",get:function(){return this._byteRange?this._byteRange:[]}},{key:"byteRangeStartOffset",get:function(){return this.byteRange[0]}},{key:"byteRangeEndOffset",get:function(){return this.byteRange[1]}},{key:"decryptdata",get:function(){if(!this.levelkey&&!this._decryptdata)return null;if(!this._decryptdata&&this.levelkey){var e=this.sn;"number"!=typeof e&&(this.levelkey&&"AES-128"===this.levelkey.method&&!this.levelkey.iv&&d.b.warn('missing IV for initialization segment with method="'+this.levelkey.method+'" - compliance issue'),e=0),this._decryptdata=this.setDecryptDataFromLevelKey(this.levelkey,e)}return this._decryptdata}},{key:"endProgramDateTime",get:function(){if(null===this.programDateTime)return null;if(!Object(l.a)(this.programDateTime))return null;var e=Object(l.a)(this.duration)?this.duration:0;return this.programDateTime+1e3*e}},{key:"encrypted",get:function(){return!(!this.decryptdata||null===this.decryptdata.uri||null!==this.decryptdata.key)}}])&&m(t.prototype,r),i&&m(t,i),e}();function b(e,t){for(var r=0;rNumber.MAX_SAFE_INTEGER?1/0:t},t.hexadecimalInteger=function(e){if(this[e]){var t=(this[e]||"0x").slice(2);t=(1&t.length?"0":"")+t;for(var r=new Uint8Array(t.length/2),i=0;iNumber.MAX_SAFE_INTEGER?1/0:t},t.decimalFloatingPoint=function(e){return parseFloat(this[e])},t.enumeratedString=function(e){return this[e]},t.decimalResolution=function(e){var t=E.exec(this[e]);if(null!==t)return{width:parseInt(t[1],10),height:parseInt(t[2],10)}},e.parseAttrList=function(e){var t,r={};for(S.lastIndex=0;null!==(t=S.exec(e));){var i=t[2];0===i.indexOf('"')&&i.lastIndexOf('"')===i.length-1&&(i=i.slice(1,-1)),r[t[1]]=i}return r},e}(),R={audio:{a3ds:!0,"ac-3":!0,"ac-4":!0,alac:!0,alaw:!0,dra1:!0,"dts+":!0,"dts-":!0,dtsc:!0,dtse:!0,dtsh:!0,"ec-3":!0,enca:!0,g719:!0,g726:!0,m4ae:!0,mha1:!0,mha2:!0,mhm1:!0,mhm2:!0,mlpa:!0,mp4a:!0,"raw ":!0,Opus:!0,samr:!0,sawb:!0,sawp:!0,sevc:!0,sqcp:!0,ssmv:!0,twos:!0,ulaw:!0},video:{avc1:!0,avc2:!0,avc3:!0,avc4:!0,avcp:!0,drac:!0,dvav:!0,dvhe:!0,encv:!0,hev1:!0,hvc1:!0,mjp2:!0,mp4v:!0,mvc1:!0,mvc2:!0,mvc3:!0,mvc4:!0,resv:!0,rv60:!0,s263:!0,svc1:!0,svc2:!0,"vc-1":!0,vp08:!0,vp09:!0}};function A(e,t){return MediaSource.isTypeSupported((t||"video")+'/mp4;codecs="'+e+'"')}var k=/(?:#EXT-X-STREAM-INF:([^\n\r]*)[\r\n]+([^\r\n]+)|#EXT-X-SESSION-DATA:([^\n\r]*)[\r\n]+)/g,w=/#EXT-X-MEDIA:(.*)/g,L=new RegExp([/#EXTINF:\s*(\d*(?:\.\d+)?)(?:,(.*)\s+)?/.source,/|(?!#)([\S+ ?]+)/.source,/|#EXT-X-BYTERANGE:*(.+)/.source,/|#EXT-X-PROGRAM-DATE-TIME:(.+)/.source,/|#.*/.source].join(""),"g"),D=/(?:(?:#(EXTM3U))|(?:#EXT-X-(PLAYLIST-TYPE):(.+))|(?:#EXT-X-(MEDIA-SEQUENCE): *(\d+))|(?:#EXT-X-(TARGETDURATION): *(\d+))|(?:#EXT-X-(KEY):(.+))|(?:#EXT-X-(START):(.+))|(?:#EXT-X-(ENDLIST))|(?:#EXT-X-(DISCONTINUITY-SEQ)UENCE:(\d+))|(?:#EXT-X-(DIS)CONTINUITY))|(?:#EXT-X-(VERSION):(\d+))|(?:#EXT-X-(MAP):(.+))|(?:(#)([^:]*):(.*))|(?:(#)(.*))(?:.*)\r?\n?/,O=/\.(mp4|m4s|m4v|m4a)$/i,C=function(){function e(){}return e.findGroup=function(e,t){for(var r=0;r2?(t=r.shift()+".",t+=parseInt(r.shift()).toString(16),t+=("000"+parseInt(r.shift()).toString(16)).substr(-4)):t=e,t},e.resolve=function(e,t){return s.buildAbsoluteURL(t,e,{alwaysNormalize:!0})},e.parseMasterPlaylist=function(t,r){var i,a=[],n={},s=!1;function o(e,t){["video","audio"].forEach((function(r){var i=e.filter((function(e){return function(e,t){var r=R[t];return!!r&&!0===r[e.slice(0,4)]}(e,r)}));if(i.length){var a=i.filter((function(e){return 0===e.lastIndexOf("avc1",0)||0===e.lastIndexOf("mp4a",0)}));t[r+"Codec"]=a.length>0?a[0]:i[0],e=e.filter((function(e){return-1===i.indexOf(e)}))}})),t.unknownCodecs=e}for(k.lastIndex=0;null!=(i=k.exec(t));)if(i[1]){var l={},u=l.attrs=new _(i[1]);l.url=e.resolve(i[2],r);var d=u.decimalResolution("RESOLUTION");d&&(l.width=d.width,l.height=d.height),l.bitrate=u.decimalInteger("AVERAGE-BANDWIDTH")||u.decimalInteger("BANDWIDTH"),l.name=u.NAME,o([].concat((u.CODECS||"").split(/[ ,]+/)),l),l.videoCodec&&-1!==l.videoCodec.indexOf("avc1")&&(l.videoCodec=e.convertAVC1ToAVCOTI(l.videoCodec)),a.push(l)}else if(i[3]){var c=new _(i[3]);c["DATA-ID"]&&(s=!0,n[c["DATA-ID"]]=c)}return{levels:a,sessionData:s?n:null}},e.parseMasterPlaylistMedia=function(t,r,i,a){var n;void 0===a&&(a=[]);var s=[],o=0;for(w.lastIndex=0;null!==(n=w.exec(t));){var l=new _(n[1]);if(l.TYPE===i){var u={attrs:l,id:o++,groupId:l["GROUP-ID"],instreamId:l["INSTREAM-ID"],name:l.NAME||l.LANGUAGE,type:i,default:"YES"===l.DEFAULT,autoselect:"YES"===l.AUTOSELECT,forced:"YES"===l.FORCED,lang:l.LANGUAGE};if(l.URI&&(u.url=e.resolve(l.URI,r)),a.length){var d=e.findGroup(a,u.groupId);u.audioCodec=d?d.codec:a[0].codec}s.push(u)}}return s},e.parseLevelPlaylist=function(e,t,r,i,a){var n,s,o,u=0,c=0,h=new T(t),f=0,g=null,p=new y,m=null;for(L.lastIndex=0;null!==(n=L.exec(e));){var b=n[1];if(b){p.duration=parseFloat(b);var E=(" "+n[2]).slice(1);p.title=E||null,p.tagList.push(E?["INF",b,E]:["INF",b])}else if(n[3]){if(Object(l.a)(p.duration)){var S=u++;p.type=i,p.start=c,o&&(p.levelkey=o),p.sn=S,p.level=r,p.cc=f,p.urlId=a,p.baseurl=t,p.relurl=(" "+n[3]).slice(1),I(p,g),h.fragments.push(p),g=p,c+=p.duration,p=new y}}else if(n[4]){var R=(" "+n[4]).slice(1);g?p.setByteRange(R,g):p.setByteRange(R)}else if(n[5])p.rawProgramDateTime=(" "+n[5]).slice(1),p.tagList.push(["PROGRAM-DATE-TIME",p.rawProgramDateTime]),null===m&&(m=h.fragments.length);else{if(!(n=n[0].match(D))){d.b.warn("No matches on slow regex match for level playlist!");continue}for(s=1;s=0&&(o.method=C,o.key=null,o.iv=x));break;case"START":var M=new _(A).decimalFloatingPoint("TIME-OFFSET");Object(l.a)(M)&&(h.startTimeOffset=M);break;case"MAP":var F=new _(A);p.relurl=F.URI,F.BYTERANGE&&p.setByteRange(F.BYTERANGE),p.baseurl=t,p.level=r,p.type=i,p.sn="initSegment",h.initSegment=p,(p=new y).rawProgramDateTime=h.initSegment.rawProgramDateTime;break;default:d.b.warn("line parsed but not handled: "+n)}}}return(p=g)&&!p.relurl&&(h.fragments.pop(),c-=p.duration),h.totalduration=c,h.averagetargetduration=c/h.fragments.length,h.endSN=u-1,h.startCC=h.fragments[0]?h.fragments[0].cc:0,h.endCC=f,!h.initSegment&&h.fragments.length&&h.fragments.every((function(e){return O.test(e.relurl)}))&&(d.b.warn("MP4 fragments found but no init segment (probably no MAP, incomplete M3U8), trying to fetch SIDX"),(p=new y).relurl=h.fragments[0].relurl,p.baseurl=t,p.level=r,p.type=i,p.sn="initSegment",h.initSegment=p,h.needSidxRanges=!0),m&&function(e,t){for(var r=e[t],i=t-1;i>=0;i--){var a=e[i];a.programDateTime=r.programDateTime-1e3*a.duration,r=a}}(h.fragments,m),h},e}();function I(e,t){e.rawProgramDateTime?e.programDateTime=Date.parse(e.rawProgramDateTime):(null==t?void 0:t.programDateTime)&&(e.programDateTime=t.endProgramDateTime),Object(l.a)(e.programDateTime)||(e.programDateTime=null,e.rawProgramDateTime=null)}var P=window.performance,x=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.MANIFEST_LOADING,u.a.LEVEL_LOADING,u.a.AUDIO_TRACK_LOADING,u.a.SUBTITLE_TRACK_LOADING)||this).loaders={},r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r,i.canHaveQualityLevels=function(e){return e!==a.AUDIO_TRACK&&e!==a.SUBTITLE_TRACK},i.mapContextToLevelType=function(e){switch(e.type){case a.AUDIO_TRACK:return n.AUDIO;case a.SUBTITLE_TRACK:return n.SUBTITLE;default:return n.MAIN}},i.getResponseUrl=function(e,t){var r=e.url;return void 0!==r&&0!==r.indexOf("data:")||(r=t.url),r};var s=i.prototype;return s.createInternalLoader=function(e){var t=this.hls.config,r=t.pLoader,i=t.loader,a=new(r||i)(t);return e.loader=a,this.loaders[e.type]=a,a},s.getInternalLoader=function(e){return this.loaders[e.type]},s.resetInternalLoader=function(e){this.loaders[e]&&delete this.loaders[e]},s.destroyInternalLoaders=function(){for(var e in this.loaders){var t=this.loaders[e];t&&t.destroy(),this.resetInternalLoader(e)}},s.destroy=function(){this.destroyInternalLoaders(),e.prototype.destroy.call(this)},s.onManifestLoading=function(e){this.load({url:e.url,type:a.MANIFEST,level:0,id:null,responseType:"text"})},s.onLevelLoading=function(e){this.load({url:e.url,type:a.LEVEL,level:e.level,id:e.id,responseType:"text"})},s.onAudioTrackLoading=function(e){this.load({url:e.url,type:a.AUDIO_TRACK,level:null,id:e.id,responseType:"text"})},s.onSubtitleTrackLoading=function(e){this.load({url:e.url,type:a.SUBTITLE_TRACK,level:null,id:e.id,responseType:"text"})},s.load=function(e){var t=this.hls.config;d.b.debug("Loading playlist of type "+e.type+", level: "+e.level+", id: "+e.id);var r,i,n,s,o=this.getInternalLoader(e);if(o){var l=o.context;if(l&&l.url===e.url)return d.b.trace("playlist request ongoing"),!1;d.b.warn("aborting previous loader for type: "+e.type),o.abort()}switch(e.type){case a.MANIFEST:r=t.manifestLoadingMaxRetry,i=t.manifestLoadingTimeOut,n=t.manifestLoadingRetryDelay,s=t.manifestLoadingMaxRetryTimeout;break;case a.LEVEL:r=0,s=0,n=0,i=t.levelLoadingTimeOut;break;default:r=t.levelLoadingMaxRetry,i=t.levelLoadingTimeOut,n=t.levelLoadingRetryDelay,s=t.levelLoadingMaxRetryTimeout}o=this.createInternalLoader(e);var u={timeout:i,maxRetry:r,retryDelay:n,maxRetryDelay:s},c={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};return d.b.debug("Calling internal loader delegate for URL: "+e.url),o.load(e,u,c),!0},s.loadsuccess=function(e,t,r,i){if(void 0===i&&(i=null),r.isSidxRequest)return this._handleSidxRequest(e,r),void this._handlePlaylistLoaded(e,t,r,i);if(this.resetInternalLoader(r.type),"string"!=typeof e.data)throw new Error('expected responseType of "text" for PlaylistLoader');var a=e.data;t.tload=P.now(),0===a.indexOf("#EXTM3U")?a.indexOf("#EXTINF:")>0||a.indexOf("#EXT-X-TARGETDURATION:")>0?this._handleTrackOrLevelPlaylist(e,t,r,i):this._handleMasterPlaylist(e,t,r,i):this._handleManifestParsingError(e,r,"no EXTM3U delimiter",i)},s.loaderror=function(e,t,r){void 0===r&&(r=null),this._handleNetworkError(t,r,!1,e)},s.loadtimeout=function(e,t,r){void 0===r&&(r=null),this._handleNetworkError(t,r,!0)},s._handleMasterPlaylist=function(e,t,r,a){var n=this.hls,s=e.data,o=i.getResponseUrl(e,r),l=C.parseMasterPlaylist(s,o),c=l.levels,h=l.sessionData;if(c.length){var f=c.map((function(e){return{id:e.attrs.AUDIO,codec:e.audioCodec}})),g=C.parseMasterPlaylistMedia(s,o,"AUDIO",f),p=C.parseMasterPlaylistMedia(s,o,"SUBTITLES"),v=C.parseMasterPlaylistMedia(s,o,"CLOSED-CAPTIONS");if(g.length){var m=!1;g.forEach((function(e){e.url||(m=!0)})),!1===m&&c[0].audioCodec&&!c[0].attrs.AUDIO&&(d.b.log("audio codec signaled in quality level, but no embedded audio track signaled, create one"),g.unshift({type:"main",name:"main",default:!1,autoselect:!1,forced:!1,id:-1,attrs:{},url:""}))}n.trigger(u.a.MANIFEST_LOADED,{levels:c,audioTracks:g,subtitles:p,captions:v,url:o,stats:t,networkDetails:a,sessionData:h})}else this._handleManifestParsingError(e,r,"no level found in manifest",a)},s._handleTrackOrLevelPlaylist=function(e,t,r,n){var s=this.hls,d=r.id,c=r.level,h=r.type,f=i.getResponseUrl(e,r),g=Object(l.a)(d)?d:0,p=Object(l.a)(c)?c:g,v=i.mapContextToLevelType(r),m=C.parseLevelPlaylist(e.data,f,p,v,g);if(m.tload=t.tload,m.fragments.length){if(h===a.MANIFEST){var y={url:f,details:m};s.trigger(u.a.MANIFEST_LOADED,{levels:[y],audioTracks:[],url:f,stats:t,networkDetails:n,sessionData:null})}if(t.tparsed=P.now(),m.needSidxRanges){var b=m.initSegment.url;this.load({url:b,isSidxRequest:!0,type:h,level:c,levelDetails:m,id:d,rangeStart:0,rangeEnd:2048,responseType:"arraybuffer"})}else r.levelDetails=m,this._handlePlaylistLoaded(e,t,r,n)}else s.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.LEVEL_EMPTY_ERROR,fatal:!1,url:f,reason:"no fragments found in level",level:"number"==typeof r.level?r.level:void 0})},s._handleSidxRequest=function(e,t){if("string"==typeof e.data)throw new Error("sidx request must be made with responseType of array buffer");var r=f.a.parseSegmentIndex(new Uint8Array(e.data));if(r){var i=r.references,a=t.levelDetails;i.forEach((function(e,t){var r=e.info;if(a){var i=a.fragments[t];0===i.byteRange.length&&i.setByteRange(String(1+r.end-r.start)+"@"+String(r.start))}})),a&&a.initSegment.setByteRange(String(r.moovEndOffset)+"@0")}},s._handleManifestParsingError=function(e,t,r,i){this.hls.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.MANIFEST_PARSING_ERROR,fatal:!0,url:e.url,reason:r,networkDetails:i})},s._handleNetworkError=function(e,t,r,i){var n,s;void 0===r&&(r=!1),void 0===i&&(i=null),d.b.info("A network error occured while loading a "+e.type+"-type playlist");var l=this.getInternalLoader(e);switch(e.type){case a.MANIFEST:n=r?o.a.MANIFEST_LOAD_TIMEOUT:o.a.MANIFEST_LOAD_ERROR,s=!0;break;case a.LEVEL:n=r?o.a.LEVEL_LOAD_TIMEOUT:o.a.LEVEL_LOAD_ERROR,s=!1;break;case a.AUDIO_TRACK:n=r?o.a.AUDIO_TRACK_LOAD_TIMEOUT:o.a.AUDIO_TRACK_LOAD_ERROR,s=!1;break;default:s=!1}l&&(l.abort(),this.resetInternalLoader(e.type));var c={type:o.b.NETWORK_ERROR,details:n,fatal:s,url:e.url,loader:l,context:e,networkDetails:t};i&&(c.response=i),this.hls.trigger(u.a.ERROR,c)},s._handlePlaylistLoaded=function(e,t,r,n){var s=r.type,o=r.level,l=r.id,d=r.levelDetails;if(d&&d.targetduration)if(i.canHaveQualityLevels(r.type))this.hls.trigger(u.a.LEVEL_LOADED,{details:d,level:o||0,id:l||0,stats:t,networkDetails:n});else switch(s){case a.AUDIO_TRACK:this.hls.trigger(u.a.AUDIO_TRACK_LOADED,{details:d,id:l,stats:t,networkDetails:n});break;case a.SUBTITLE_TRACK:this.hls.trigger(u.a.SUBTITLE_TRACK_LOADED,{details:d,id:l,stats:t,networkDetails:n})}else this._handleManifestParsingError(e,r,"invalid target duration",n)},i}(h);var M=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.FRAG_LOADING)||this).loaders={},r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){var t=this.loaders;for(var r in t){var i=t[r];i&&i.destroy()}this.loaders={},e.prototype.destroy.call(this)},a.onFragLoading=function(e){var t=e.frag,r=t.type,i=this.loaders,a=this.hls.config,n=a.fLoader,s=a.loader;t.loaded=0;var o,u,c,h=i[r];h&&(d.b.warn("abort previous fragment loader for type: "+r),h.abort()),h=i[r]=t.loader=a.fLoader?new n(a):new s(a),o={url:t.url,frag:t,responseType:"arraybuffer",progressData:!1};var f=t.byteRangeStartOffset,g=t.byteRangeEndOffset;Object(l.a)(f)&&Object(l.a)(g)&&(o.rangeStart=f,o.rangeEnd=g),u={timeout:a.fragLoadingTimeOut,maxRetry:0,retryDelay:0,maxRetryDelay:a.fragLoadingMaxRetryTimeout},c={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this),onProgress:this.loadprogress.bind(this)},h.load(o,u,c)},a.loadsuccess=function(e,t,r,i){void 0===i&&(i=null);var a=e.data,n=r.frag;n.loader=void 0,this.loaders[n.type]=void 0,this.hls.trigger(u.a.FRAG_LOADED,{payload:a,frag:n,stats:t,networkDetails:i})},a.loaderror=function(e,t,r){void 0===r&&(r=null);var i=t.frag,a=i.loader;a&&a.abort(),this.loaders[i.type]=void 0,this.hls.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_ERROR,fatal:!1,frag:t.frag,response:e,networkDetails:r})},a.loadtimeout=function(e,t,r){void 0===r&&(r=null);var i=t.frag,a=i.loader;a&&a.abort(),this.loaders[i.type]=void 0,this.hls.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.FRAG_LOAD_TIMEOUT,fatal:!1,frag:t.frag,networkDetails:r})},a.loadprogress=function(e,t,r,i){void 0===i&&(i=null);var a=t.frag;a.loaded=e.loaded,this.hls.trigger(u.a.FRAG_LOAD_PROGRESS,{frag:a,stats:e,networkDetails:i})},i}(h);var F=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.KEY_LOADING)||this).loaders={},r.decryptkey=null,r.decrypturl=null,r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){for(var t in this.loaders){var r=this.loaders[t];r&&r.destroy()}this.loaders={},e.prototype.destroy.call(this)},a.onKeyLoading=function(e){var t=e.frag,r=t.type,i=this.loaders[r];if(t.decryptdata){var a=t.decryptdata.uri;if(a!==this.decrypturl||null===this.decryptkey){var n=this.hls.config;if(i&&(d.b.warn("abort previous key loader for type:"+r),i.abort()),!a)return void d.b.warn("key uri is falsy");t.loader=this.loaders[r]=new n.loader(n),this.decrypturl=a,this.decryptkey=null;var s={url:a,frag:t,responseType:"arraybuffer"},o={timeout:n.fragLoadingTimeOut,maxRetry:0,retryDelay:n.fragLoadingRetryDelay,maxRetryDelay:n.fragLoadingMaxRetryTimeout},l={onSuccess:this.loadsuccess.bind(this),onError:this.loaderror.bind(this),onTimeout:this.loadtimeout.bind(this)};t.loader.load(s,o,l)}else this.decryptkey&&(t.decryptdata.key=this.decryptkey,this.hls.trigger(u.a.KEY_LOADED,{frag:t}))}else d.b.warn("Missing decryption data on fragment in onKeyLoading")},a.loadsuccess=function(e,t,r){var i=r.frag;i.decryptdata?(this.decryptkey=i.decryptdata.key=new Uint8Array(e.data),i.loader=void 0,delete this.loaders[i.type],this.hls.trigger(u.a.KEY_LOADED,{frag:i})):d.b.error("after key load, decryptdata unset")},a.loaderror=function(e,t){var r=t.frag,i=r.loader;i&&i.abort(),delete this.loaders[r.type],this.hls.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.KEY_LOAD_ERROR,fatal:!1,frag:r,response:e})},a.loadtimeout=function(e,t){var r=t.frag,i=r.loader;i&&i.abort(),delete this.loaders[r.type],this.hls.trigger(u.a.ERROR,{type:o.b.NETWORK_ERROR,details:o.a.KEY_LOAD_TIMEOUT,fatal:!1,frag:r})},i}(h);var U="NOT_LOADED",N="APPENDING",B="PARTIAL",G="OK",K=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.BUFFER_APPENDED,u.a.FRAG_BUFFERED,u.a.FRAG_LOADED)||this).bufferPadding=.2,r.fragments=Object.create(null),r.timeRanges=Object.create(null),r.config=t.config,r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){this.fragments=Object.create(null),this.timeRanges=Object.create(null),this.config=null,h.prototype.destroy.call(this),e.prototype.destroy.call(this)},a.getBufferedFrag=function(e,t){var r=this.fragments,i=Object.keys(r).filter((function(i){var a=r[i];if(a.body.type!==t)return!1;if(!a.buffered)return!1;var n=a.body;return n.startPTS<=e&&e<=n.endPTS}));if(0===i.length)return null;var a=i.pop();return r[a].body},a.detectEvictedFragments=function(e,t){var r=this;Object.keys(this.fragments).forEach((function(i){var a=r.fragments[i];if(a&&a.buffered){var n=a.range[e];if(n)for(var s=n.time,o=0;o=i&&t<=a){n.push({startPTS:Math.max(e,r.start(o)),endPTS:Math.min(t,r.end(o))});break}if(ei)n.push({startPTS:Math.max(e,r.start(o)),endPTS:Math.min(t,r.end(o))}),s=!0;else if(t<=i)break}return{time:n,partial:s}},a.getFragmentKey=function(e){return e.type+"_"+e.level+"_"+e.urlId+"_"+e.sn},a.getPartialFragment=function(e){var t,r,i,a=this,n=null,s=0;return Object.keys(this.fragments).forEach((function(o){var l=a.fragments[o];a.isPartial(l)&&(r=l.body.startPTS-a.bufferPadding,i=l.body.endPTS+a.bufferPadding,e>=r&&e<=i&&(t=Math.min(e-r,i-e),s<=t&&(n=l.body,s=t)))})),n},a.getState=function(e){var t=this.getFragmentKey(e),r=this.fragments[t],i=U;return void 0!==r&&(i=r.buffered?!0===this.isPartial(r)?B:G:N),i},a.isPartial=function(e){return!0===e.buffered&&(void 0!==e.range.video&&!0===e.range.video.partial||void 0!==e.range.audio&&!0===e.range.audio.partial)},a.isTimeBuffered=function(e,t,r){for(var i,a,n=0;n=i&&t<=a)return!0;if(t<=i)return!1}return!1},a.onFragLoaded=function(e){var t=e.frag;Object(l.a)(t.sn)&&!t.bitrateTest&&(this.fragments[this.getFragmentKey(t)]={body:t,range:Object.create(null),buffered:!1})},a.onBufferAppended=function(e){var t=this;this.timeRanges=e.timeRanges,Object.keys(this.timeRanges).forEach((function(e){var r=t.timeRanges[e];t.detectEvictedFragments(e,r)}))},a.onFragBuffered=function(e){this.detectPartialFragments(e.frag)},a.hasFragment=function(e){var t=this.getFragmentKey(e);return void 0!==this.fragments[t]},a.removeFragment=function(e){var t=this.getFragmentKey(e);delete this.fragments[t]},a.removeAllFragments=function(){this.fragments=Object.create(null)},i}(h),j={search:function(e,t){for(var r=0,i=e.length-1,a=null,n=null;r<=i;){var s=t(n=e[a=(r+i)/2|0]);if(s>0)r=a+1;else{if(!(s<0))return n;i=a-1}}return null}},H=function(){function e(){}return e.isBuffered=function(e,t){try{if(e)for(var r=e.buffered,i=0;i=r.start(i)&&t<=r.end(i))return!0}catch(e){}return!1},e.bufferInfo=function(e,t,r){try{if(e){var i,a=e.buffered,n=[];for(i=0;is&&(i[n-1].end=e[a].end):i.push(e[a])}else i.push(e[a])}else i=e;for(var o,l=0,u=t,d=t,c=0;c=h&&t1?t-1:0),i=1;it?(i.duration=n-i.start,i.duration<0&&d.b.warn("negative duration computed for frag "+i.sn+",level "+i.level+", there should be some duration drift between playlist and fragment!")):(a.duration=i.start-n,a.duration<0&&d.b.warn("negative duration computed for frag "+a.sn+",level "+a.level+", there should be some duration drift between playlist and fragment!")):a.start=r>t?i.start+i.duration:Math.max(i.start-a.duration,0)}function te(e,t,r,i,a,n){var s=r;if(Object(l.a)(t.startPTS)){var o=Math.abs(t.startPTS-r);Object(l.a)(t.deltaPTS)?t.deltaPTS=Math.max(o,t.deltaPTS):t.deltaPTS=o,s=Math.max(r,t.startPTS),r=Math.min(r,t.startPTS),i=Math.max(i,t.endPTS),a=Math.min(a,t.startDTS),n=Math.max(n,t.endDTS)}var u=r-t.start;t.start=t.startPTS=r,t.maxStartPTS=s,t.endPTS=i,t.startDTS=a,t.endDTS=n,t.duration=i-r;var d,c,h,f=t.sn;if(!e||fe.endSN)return 0;for(d=f-e.startSN,(c=e.fragments)[d]=t,h=d;h>0;h--)ee(c,h,h-1);for(h=d;hi.length)return;for(var n=0;nr.startCC||e&&e.cc=(e[e.length-1].endProgramDateTime||0))return null;r=r||0;for(var i=0;ie&&r.start?-1:0}function ce(e,t,r){var i=1e3*Math.min(t,r.duration+(r.deltaPTS?r.deltaPTS:0));return(r.endProgramDateTime||0)-i>e}var he=function(){function e(e,t,r,i){this.config=e,this.media=t,this.fragmentTracker=r,this.hls=i,this.nudgeRetry=0,this.stallReported=!1,this.stalled=null,this.moved=!1,this.seeking=!1}var t=e.prototype;return t.poll=function(e){var t=this.config,r=this.media,i=this.stalled,a=r.currentTime,n=r.seeking,s=this.seeking&&!n,o=!this.seeking&&n;if(this.seeking=n,a===e){if((o||s)&&(this.stalled=null),!r.paused&&!r.ended&&0!==r.playbackRate&&r.buffered.length){var l=H.bufferInfo(r,a,0),u=l.len>0,c=l.nextStart||0;if(u||c){if(n){var h=l.len>2,f=!c||c-a>2&&!this.fragmentTracker.getPartialFragment(a);if(h||f)return;this.moved=!1}if(!this.moved&&this.stalled){var g=Math.max(c,l.start||0)-a;if(g>0&&g<=2)return void this._trySkipBufferHole(null)}var p=self.performance.now();if(null!==i){var v=p-i;!n&&v>=250&&this._reportStall(l.len);var m=H.bufferInfo(r,a,t.maxBufferHole);this._tryFixBufferStall(m,v)}else this.stalled=p}}}else if(this.moved=!0,null!==i){if(this.stallReported){var y=self.performance.now()-i;d.b.warn("playback not stuck anymore @"+a+", after "+Math.round(y)+"ms"),this.stallReported=!1}this.stalled=null,this.nudgeRetry=0}},t._tryFixBufferStall=function(e,t){var r=this.config,i=this.fragmentTracker,a=this.media.currentTime,n=i.getPartialFragment(a);if(n&&this._trySkipBufferHole(n))return;e.len>r.maxBufferHole&&t>1e3*r.highBufferWatchdogPeriod&&(d.b.warn("Trying to nudge playhead over buffer-hole"),this.stalled=null,this._tryNudgeBuffer())},t._reportStall=function(e){var t=this.hls,r=this.media;this.stallReported||(this.stallReported=!0,d.b.warn("Playback stalling at @"+r.currentTime+" due to low buffer (buffer="+e+")"),t.trigger(u.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_STALLED_ERROR,fatal:!1,buffer:e}))},t._trySkipBufferHole=function(e){for(var t=this.config,r=this.hls,i=this.media,a=i.currentTime,n=0,s=0;s=n&&a1?i-1:0),n=1;n1&&(this.clearNextTick(),this._tickTimer=self.setTimeout(this._boundTick,0)),this._tickCallCount=0)},a.doTick=function(){},i}(h);var pe="STOPPED",ve="STARTING",me="IDLE",ye="PAUSED",be="KEY_LOADING",Te="FRAG_LOADING",Ee="FRAG_LOADING_WAITING_RETRY",Se="WAITING_TRACK",_e="PARSING",Re="PARSED",Ae="BUFFER_FLUSHING",ke="ENDED",we="ERROR",Le="WAITING_INIT_PTS",De="WAITING_LEVEL",Oe=function(e){var t,r;function i(){return e.apply(this,arguments)||this}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.doTick=function(){},a.startLoad=function(){},a.stopLoad=function(){var e=this.fragCurrent;e&&(e.loader&&e.loader.abort(),this.fragmentTracker.removeFragment(e)),this.demuxer&&(this.demuxer.destroy(),this.demuxer=null),this.fragCurrent=null,this.fragPrevious=null,this.clearInterval(),this.clearNextTick(),this.state=pe},a._streamEnded=function(e,t){var r=this.fragCurrent,i=this.fragmentTracker;if(!t.live&&r&&!r.backtracked&&r.sn===t.endSN&&!e.nextStart){var a=i.getState(r);return a===B||a===G}return!1},a.onMediaSeeking=function(){var e=this.config,t=this.media,r=this.mediaBuffer,i=this.state,a=t?t.currentTime:null,n=H.bufferInfo(r||t,a,this.config.maxBufferHole);if(Object(l.a)(a)&&d.b.log("media seeking to "+a.toFixed(3)),i===Te){var s=this.fragCurrent;if(0===n.len&&s){var o=e.maxFragLookUpTolerance,u=s.start-o,c=s.start+s.duration+o;ac?(s.loader&&(d.b.log("seeking outside of buffer while fragment load in progress, cancel fragment load"),s.loader.abort()),this.fragCurrent=null,this.fragPrevious=null,this.state=me):d.b.log("seeking outside of buffer but within currently loaded fragment range")}}else i===ke&&(0===n.len&&(this.fragPrevious=null,this.fragCurrent=null),this.state=me);t&&(this.lastCurrentTime=a),this.loadedmetadata||(this.nextLoadPosition=this.startPosition=a),this.tick()},a.onMediaEnded=function(){this.startPosition=this.lastCurrentTime=0},a.onHandlerDestroying=function(){this.stopLoad(),e.prototype.onHandlerDestroying.call(this)},a.onHandlerDestroyed=function(){this.state=pe,this.fragmentTracker=null},a.computeLivePosition=function(e,t){var r=void 0!==this.config.liveSyncDuration?this.config.liveSyncDuration:this.config.liveSyncDurationCount*t.targetduration;return e+Math.max(0,t.totalduration-r)},i}(ge);function Ce(e,t){for(var r=0;r0&&-1===e&&(d.b.log("override startPosition with lastCurrentTime @"+t.toFixed(3)),e=t),this.state=me,this.nextLoadPosition=this.startPosition=this.lastCurrentTime=e,this.tick()}else this.forceStartLoad=!0,this.state=pe},h.stopLoad=function(){this.forceStartLoad=!1,e.prototype.stopLoad.call(this)},h.doTick=function(){switch(this.state){case Ae:this.fragLoadError=0;break;case me:this._doTickIdle();break;case De:var e=this.levels[this.level];e&&e.details&&(this.state=me);break;case Ee:var t=window.performance.now(),r=this.retryDate;(!r||t>=r||this.media&&this.media.seeking)&&(d.b.log("mediaController: retryDate reached, switch back to IDLE state"),this.state=me)}this._checkBuffer(),this._checkFragmentChanged()},h._doTickIdle=function(){var e=this.hls,t=e.config,r=this.media;if(void 0!==this.levelLastLoaded&&(r||!this.startFragRequested&&t.startFragPrefetch))if(this.altAudio&&this.audioOnly)this.demuxer.frag=null;else{var i;i=this.loadedmetadata?r.currentTime:this.nextLoadPosition;var a=e.nextLoadLevel,n=this.levels[a];if(n){var s,o=n.bitrate;s=o?Math.max(8*t.maxBufferSize/o,t.maxBufferLength):t.maxBufferLength,s=Math.min(s,t.maxMaxBufferLength);var l=i=s)){d.b.trace("buffer length of "+h.toFixed(3)+" is below max of "+s.toFixed(3)+". checking for more payload ..."),this.level=e.nextLoadLevel=a;var f=n.details;if(!f||f.live&&this.levelLastLoaded!==a)this.state=De;else{if(this._streamEnded(c,f)){var g={};return this.altAudio&&(g.type="video"),this.hls.trigger(u.a.BUFFER_EOS,g),void(this.state=ke)}this._fetchPayloadOrEos(i,c,f)}}}}},h._fetchPayloadOrEos=function(e,t,r){var i=this.fragPrevious,a=(this.level,r.fragments),n=a.length;if(0!==n){var s,o=a[0].start,l=a[n-1].start+a[n-1].duration,u=t.end;if(r.initSegment&&!r.initSegment.data)s=r.initSegment;else if(r.live){var c=this.config.initialLiveManifestSize;if(nh&&h>u.currentTime&&(d.b.log("buffer end: "+t.toFixed(3)+" is located too far from the end of live sliding playlist, reset currentTime to : "+h.toFixed(3)),u.currentTime=h),this.nextLoadPosition=h}if(e.PTSKnown&&t>i&&u&&u.readyState)return null;if(this.startFragRequested&&!e.PTSKnown&&a)if(e.hasProgramDateTime)d.b.log("live playlist, switching playlist, load frag with same PDT: "+a.programDateTime),s=le(n,a.endProgramDateTime,o.maxFragLookUpTolerance);else{var f=a.sn+1;if(f>=e.startSN&&f<=e.endSN){var g=n[f-e.startSN];a.cc===g.cc&&(s=g,d.b.log("live playlist, switching playlist, load frag with next SN: "+s.sn))}s||(s=j.search(n,(function(e){return a.cc-e.cc})))&&d.b.log("live playlist, switching playlist, load frag with same CC: "+s.sn)}return s},h._findFragment=function(e,t,r,i,a,n,s){var o,l=this.hls.config;an-l.maxFragLookUpTolerance?0:l.maxFragLookUpTolerance):o=i[r-1];if(o){var u=o.sn-s.startSN,c=t&&o.level===t.level,h=i[u-1],f=i[u+1];if(t&&o.sn===t.sn)if(c&&!o.backtracked)if(o.snl.maxBufferHole&&t.dropped&&u?(o=h,d.b.warn("Previous fragment was dropped with large PTS gap between audio and video. Maybe fragment is not starting with a keyframe? Loading previous one to try to overcome this")):(o=f,d.b.log("Re-loading fragment with SN: "+o.sn))}else o=null;else o.backtracked&&(f&&f.backtracked?(d.b.warn("Already backtracked from fragment "+f.sn+", will not backtrack to fragment "+o.sn+". Loading fragment "+f.sn),o=f):(d.b.warn("Loaded fragment with dropped frames, backtracking 1 segment to find a keyframe"),o.dropped=0,h?(o=h).backtracked=!0:u&&(o=null)))}return o},h._loadKey=function(e,t){d.b.log("Loading key for "+e.sn+" of ["+t.startSN+" ,"+t.endSN+"],level "+this.level),this.state=be,this.hls.trigger(u.a.KEY_LOADING,{frag:e})},h._loadFragment=function(e,t,r,i){var a=this.fragmentTracker.getState(e);this.fragCurrent=e,"initSegment"!==e.sn&&(this.startFragRequested=!0),Object(l.a)(e.sn)&&!e.bitrateTest&&(this.nextLoadPosition=e.start+e.duration),e.backtracked||a===U||a===B?(e.autoLevel=this.hls.autoLevelEnabled,e.bitrateTest=this.bitrateTest,d.b.log("Loading "+e.sn+" of ["+t.startSN+" ,"+t.endSN+"],level "+this.level+", currentTime:"+r.toFixed(3)+",bufferEnd:"+i.toFixed(3)),this.hls.trigger(u.a.FRAG_LOADING,{frag:e}),this.demuxer||(this.demuxer=new J(this.hls,"main")),this.state=Te):a===N&&this._reduceMaxBufferLength(e.duration)&&this.fragmentTracker.removeFragment(e)},h.getBufferedFrag=function(e){return this.fragmentTracker.getBufferedFrag(e,n.MAIN)},h.followingBufferedFrag=function(e){return e?this.getBufferedFrag(e.endPTS+.5):null},h._checkFragmentChanged=function(){var e,t,r=this.media;if(r&&r.readyState&&!1===r.seeking&&((t=r.currentTime)>this.lastCurrentTime&&(this.lastCurrentTime=t),H.isBuffered(r,t)?e=this.getBufferedFrag(t):H.isBuffered(r,t+.1)&&(e=this.getBufferedFrag(t+.1)),e)){var i=e;if(i!==this.fragPlaying){this.hls.trigger(u.a.FRAG_CHANGED,{frag:i});var a=i.level;this.fragPlaying&&this.fragPlaying.level===a||this.hls.trigger(u.a.LEVEL_SWITCHED,{level:a}),this.fragPlaying=i}}},h.immediateLevelSwitch=function(){if(d.b.log("immediateLevelSwitch"),!this.immediateSwitch){this.immediateSwitch=!0;var e,t=this.media;t?(e=t.paused,t.pause()):e=!0,this.previouslyPaused=e}var r=this.fragCurrent;r&&r.loader&&r.loader.abort(),this.fragCurrent=null,this.flushMainBuffer(0,Number.POSITIVE_INFINITY)},h.immediateLevelSwitchEnd=function(){var e=this.media;e&&e.buffered.length&&(this.immediateSwitch=!1,H.isBuffered(e,e.currentTime)&&(e.currentTime-=1e-4),this.previouslyPaused||e.play())},h.nextLevelSwitch=function(){var e=this.media;if(e&&e.readyState){var t,r,i;if((r=this.getBufferedFrag(e.currentTime))&&r.startPTS>1&&this.flushMainBuffer(0,r.startPTS-1),e.paused)t=0;else{var a=this.hls.nextLoadLevel,n=this.levels[a],s=this.fragLastKbps;t=s&&this.fragCurrent?this.fragCurrent.duration*n.bitrate/(1e3*s)+1:0}if((i=this.getBufferedFrag(e.currentTime+t))&&(i=this.followingBufferedFrag(i))){var o=this.fragCurrent;o&&o.loader&&o.loader.abort(),this.fragCurrent=null,this.flushMainBuffer(i.maxStartPTS,Number.POSITIVE_INFINITY)}}},h.flushMainBuffer=function(e,t){this.state=Ae;var r={startOffset:e,endOffset:t};this.altAudio&&(r.type="video"),this.hls.trigger(u.a.BUFFER_FLUSHING,r)},h.onMediaAttached=function(e){var t=this.media=this.mediaBuffer=e.media;this.onvseeking=this.onMediaSeeking.bind(this),this.onvseeked=this.onMediaSeeked.bind(this),this.onvended=this.onMediaEnded.bind(this),t.addEventListener("seeking",this.onvseeking),t.addEventListener("seeked",this.onvseeked),t.addEventListener("ended",this.onvended);var r=this.config;this.levels&&r.autoStartLoad&&this.hls.startLoad(r.startPosition),this.gapController=new he(r,t,this.fragmentTracker,this.hls)},h.onMediaDetaching=function(){var e=this.media;e&&e.ended&&(d.b.log("MSE detaching and video ended, reset startPosition"),this.startPosition=this.lastCurrentTime=0);var t=this.levels;t&&t.forEach((function(e){e.details&&e.details.fragments.forEach((function(e){e.backtracked=void 0}))})),e&&(e.removeEventListener("seeking",this.onvseeking),e.removeEventListener("seeked",this.onvseeked),e.removeEventListener("ended",this.onvended),this.onvseeking=this.onvseeked=this.onvended=null),this.fragmentTracker.removeAllFragments(),this.media=this.mediaBuffer=null,this.loadedmetadata=!1,this.stopLoad()},h.onMediaSeeked=function(){var e=this.media,t=e?e.currentTime:void 0;Object(l.a)(t)&&d.b.log("media seeked to "+t.toFixed(3)),this.tick()},h.onManifestLoading=function(){d.b.log("trigger BUFFER_RESET"),this.hls.trigger(u.a.BUFFER_RESET),this.fragmentTracker.removeAllFragments(),this.stalled=!1,this.startPosition=this.lastCurrentTime=0},h.onManifestParsed=function(e){var t,r=!1,i=!1;e.levels.forEach((function(e){(t=e.audioCodec)&&(-1!==t.indexOf("mp4a.40.2")&&(r=!0),-1!==t.indexOf("mp4a.40.5")&&(i=!0))})),this.audioCodecSwitch=r&&i,this.audioCodecSwitch&&d.b.log("both AAC/HE-AAC audio found in levels; declaring level codec as HE-AAC"),this.altAudio=e.altAudio,this.levels=e.levels,this.startFragRequested=!1;var a=this.config;(a.autoStartLoad||this.forceStartLoad)&&this.hls.startLoad(a.startPosition)},h.onLevelLoaded=function(e){var t=e.details,r=e.level,i=this.levels[this.levelLastLoaded],a=this.levels[r],n=t.totalduration,s=0;if(d.b.log("level "+r+" loaded ["+t.startSN+","+t.endSN+"],duration:"+n),t.live){var o=a.details;o&&t.fragments.length>0?(re(o,t),s=t.fragments[0].start,this.liveSyncPosition=this.computeLivePosition(s,o),t.PTSKnown&&Object(l.a)(s)?d.b.log("live playlist sliding:"+s.toFixed(3)):(d.b.log("live playlist - outdated PTS, unknown sliding"),oe(this.fragPrevious,i,t))):(d.b.log("live playlist - first load, unknown sliding"),t.PTSKnown=!1,oe(this.fragPrevious,i,t))}else t.PTSKnown=!1;if(a.details=t,this.levelLastLoaded=r,this.hls.trigger(u.a.LEVEL_UPDATED,{details:t,level:r}),!1===this.startFragRequested){if(-1===this.startPosition||-1===this.lastCurrentTime){var c=t.startTimeOffset;Object(l.a)(c)?(c<0&&(d.b.log("negative start time offset "+c+", count from end of last fragment"),c=s+n+c),d.b.log("start time offset found in playlist, adjust startPosition to "+c),this.startPosition=c):t.live?(this.startPosition=this.computeLivePosition(s,t),d.b.log("configure startPosition to "+this.startPosition)):this.startPosition=0,this.lastCurrentTime=this.startPosition}this.nextLoadPosition=this.startPosition}this.state===De&&(this.state=me),this.tick()},h.onKeyLoaded=function(){this.state===be&&(this.state=me,this.tick())},h.onFragLoaded=function(e){var t=this.fragCurrent,r=this.hls,i=this.levels,a=this.media,n=e.frag;if(this.state===Te&&t&&"main"===n.type&&n.level===t.level&&n.sn===t.sn){var s=e.stats,o=i[t.level],l=o.details;if(this.bitrateTest=!1,this.stats=s,d.b.log("Loaded "+t.sn+" of ["+l.startSN+" ,"+l.endSN+"],level "+t.level),n.bitrateTest&&r.nextLoadLevel)this.state=me,this.startFragRequested=!1,s.tparsed=s.tbuffered=window.performance.now(),r.trigger(u.a.FRAG_BUFFERED,{stats:s,frag:t,id:"main"}),this.tick();else if("initSegment"===n.sn)this.state=me,s.tparsed=s.tbuffered=window.performance.now(),l.initSegment.data=e.payload,r.trigger(u.a.FRAG_BUFFERED,{stats:s,frag:t,id:"main"}),this.tick();else{d.b.log("Parsing "+t.sn+" of ["+l.startSN+" ,"+l.endSN+"],level "+t.level+", cc "+t.cc),this.state=_e,this.pendingBuffering=!0,this.appended=!1,n.bitrateTest&&(n.bitrateTest=!1,this.fragmentTracker.onFragLoaded({frag:n}));var c=!(a&&a.seeking)&&(l.PTSKnown||!l.live),h=l.initSegment?l.initSegment.data:[],f=this._getAudioCodec(o);(this.demuxer=this.demuxer||new J(this.hls,"main")).push(e.payload,h,f,o.videoCodec,t,l.totalduration,c)}}this.fragLoadError=0},h.onFragParsingInitSegment=function(e){var t=this.fragCurrent,r=e.frag;if(t&&"main"===e.id&&r.sn===t.sn&&r.level===t.level&&this.state===_e){var i,a,n=e.tracks;if(this.audioOnly=n.audio&&!n.video,this.altAudio&&!this.audioOnly&&delete n.audio,a=n.audio){var s=this.levels[this.level].audioCodec,o=navigator.userAgent.toLowerCase();s&&this.audioCodecSwap&&(d.b.log("swapping playlist audio codec"),s=-1!==s.indexOf("mp4a.40.5")?"mp4a.40.2":"mp4a.40.5"),this.audioCodecSwitch&&1!==a.metadata.channelCount&&-1===o.indexOf("firefox")&&(s="mp4a.40.5"),-1!==o.indexOf("android")&&"audio/mpeg"!==a.container&&(s="mp4a.40.2",d.b.log("Android: force audio codec to "+s)),a.levelCodec=s,a.id=e.id}for(i in(a=n.video)&&(a.levelCodec=this.levels[this.level].videoCodec,a.id=e.id),this.hls.trigger(u.a.BUFFER_CODECS,n),n){a=n[i],d.b.log("main track:"+i+",container:"+a.container+",codecs[level/parsed]=["+a.levelCodec+"/"+a.codec+"]");var l=a.initSegment;l&&(this.appended=!0,this.pendingBuffering=!0,this.hls.trigger(u.a.BUFFER_APPENDING,{type:i,data:l,parent:"main",content:"initSegment"}))}this.tick()}},h.onFragParsingData=function(e){var t=this,r=this.fragCurrent,i=e.frag;if(r&&"main"===e.id&&i.sn===r.sn&&i.level===r.level&&("audio"!==e.type||!this.altAudio)&&this.state===_e){var a=this.levels[this.level],n=r;if(Object(l.a)(e.endPTS)||(e.endPTS=e.startPTS+r.duration,e.endDTS=e.startDTS+r.duration),!0===e.hasAudio&&n.addElementaryStream(p.AUDIO),!0===e.hasVideo&&n.addElementaryStream(p.VIDEO),d.b.log("Parsed "+e.type+",PTS:["+e.startPTS.toFixed(3)+","+e.endPTS.toFixed(3)+"],DTS:["+e.startDTS.toFixed(3)+"/"+e.endDTS.toFixed(3)+"],nb:"+e.nb+",dropped:"+(e.dropped||0)),"video"===e.type)if(n.dropped=e.dropped,n.dropped)if(n.backtracked)d.b.warn("Already backtracked on this fragment, appending with the gap",n.sn);else{var s=a.details;if(!s||n.sn!==s.startSN)return d.b.warn("missing video frame(s), backtracking fragment",n.sn),this.fragmentTracker.removeFragment(n),n.backtracked=!0,this.nextLoadPosition=e.startPTS,this.state=me,this.fragPrevious=n,this.demuxer&&(this.demuxer.destroy(),this.demuxer=null),void this.tick();d.b.warn("missing video frame(s) on first frag, appending with gap",n.sn)}else n.backtracked=!1;var o=te(a.details,n,e.startPTS,e.endPTS,e.startDTS,e.endDTS),c=this.hls;c.trigger(u.a.LEVEL_PTS_UPDATED,{details:a.details,level:this.level,drift:o,type:e.type,start:e.startPTS,end:e.endPTS}),[e.data1,e.data2].forEach((function(r){r&&r.length&&t.state===_e&&(t.appended=!0,t.pendingBuffering=!0,c.trigger(u.a.BUFFER_APPENDING,{type:e.type,data:r,parent:"main",content:"data"}))})),this.tick()}},h.onFragParsed=function(e){var t=this.fragCurrent,r=e.frag;t&&"main"===e.id&&r.sn===t.sn&&r.level===t.level&&this.state===_e&&(this.stats.tparsed=window.performance.now(),this.state=Re,this._checkAppendedParsed())},h.onAudioTrackSwitching=function(e){var t=!!e.url,r=e.id;if(!t){if(this.mediaBuffer!==this.media){d.b.log("switching on main audio, use media.buffered to schedule main fragment loading"),this.mediaBuffer=this.media;var i=this.fragCurrent;i.loader&&(d.b.log("switching to main audio track, cancel main fragment load"),i.loader.abort()),this.fragCurrent=null,this.fragPrevious=null,this.demuxer&&(this.demuxer.destroy(),this.demuxer=null),this.state=me}var a=this.hls;a.trigger(u.a.BUFFER_FLUSHING,{startOffset:0,endOffset:Number.POSITIVE_INFINITY,type:"audio"}),a.trigger(u.a.AUDIO_TRACK_SWITCHED,{id:r}),this.altAudio=!1}},h.onAudioTrackSwitched=function(e){var t=e.id,r=!!this.hls.audioTracks[t].url;if(r){var i=this.videoBuffer;i&&this.mediaBuffer!==i&&(d.b.log("switching on alternate audio, use video.buffered to schedule main fragment loading"),this.mediaBuffer=i)}this.altAudio=r,this.tick()},h.onBufferCreated=function(e){var t,r,i=e.tracks,a=!1;for(var n in i){var s=i[n];"main"===s.id?(r=n,t=s,"video"===n&&(this.videoBuffer=i[n].buffer)):a=!0}a&&t?(d.b.log("alternate track found, use "+r+".buffered to schedule main fragment loading"),this.mediaBuffer=t.buffer):this.mediaBuffer=this.media},h.onBufferAppended=function(e){if("main"===e.parent){var t=this.state;t!==_e&&t!==Re||(this.pendingBuffering=e.pending>0,this._checkAppendedParsed())}},h._checkAppendedParsed=function(){if(!(this.state!==Re||this.appended&&this.pendingBuffering)){var e=this.fragCurrent;if(e){var t=this.mediaBuffer?this.mediaBuffer:this.media;d.b.log("main buffered : "+ne.toString(t.buffered)),this.fragPrevious=e;var r=this.stats;r.tbuffered=window.performance.now(),this.fragLastKbps=Math.round(8*r.total/(r.tbuffered-r.tfirst)),this.hls.trigger(u.a.FRAG_BUFFERED,{stats:r,frag:e,id:"main"}),this.state=me}(this.loadedmetadata||this.startPosition<=0)&&this.tick()}},h.onError=function(e){var t=e.frag||this.fragCurrent;if(!t||"main"===t.type){var r=!!this.media&&H.isBuffered(this.media,this.media.currentTime)&&H.isBuffered(this.media,this.media.currentTime+.5);switch(e.details){case o.a.FRAG_LOAD_ERROR:case o.a.FRAG_LOAD_TIMEOUT:case o.a.KEY_LOAD_ERROR:case o.a.KEY_LOAD_TIMEOUT:if(!e.fatal)if(this.fragLoadError+1<=this.config.fragLoadingMaxRetry){var i=Math.min(Math.pow(2,this.fragLoadError)*this.config.fragLoadingRetryDelay,this.config.fragLoadingMaxRetryTimeout);d.b.warn("mediaController: frag loading failed, retry in "+i+" ms"),this.retryDate=window.performance.now()+i,this.loadedmetadata||(this.startFragRequested=!1,this.nextLoadPosition=this.startPosition),this.fragLoadError++,this.state=Ee}else d.b.error("mediaController: "+e.details+" reaches max retry, redispatch as fatal ..."),e.fatal=!0,this.state=we;break;case o.a.LEVEL_LOAD_ERROR:case o.a.LEVEL_LOAD_TIMEOUT:this.state!==we&&(e.fatal?(this.state=we,d.b.warn("streamController: "+e.details+",switch to "+this.state+" state ...")):e.levelRetry||this.state!==De||(this.state=me));break;case o.a.BUFFER_FULL_ERROR:"main"!==e.parent||this.state!==_e&&this.state!==Re||(r?(this._reduceMaxBufferLength(this.config.maxBufferLength),this.state=me):(d.b.warn("buffer full error also media.currentTime is not buffered, flush everything"),this.fragCurrent=null,this.flushMainBuffer(0,Number.POSITIVE_INFINITY)))}}},h._reduceMaxBufferLength=function(e){var t=this.config;return t.maxMaxBufferLength>=e&&(t.maxMaxBufferLength/=2,d.b.warn("main:reduce max buffer length to "+t.maxMaxBufferLength+"s"),!0)},h._checkBuffer=function(){var e=this.media;if(e&&0!==e.readyState){var t=(this.mediaBuffer?this.mediaBuffer:e).buffered;!this.loadedmetadata&&t.length?(this.loadedmetadata=!0,this._seekToStartPos()):this.immediateSwitch?this.immediateLevelSwitchEnd():this.gapController.poll(this.lastCurrentTime,t)}},h.onFragLoadEmergencyAborted=function(){this.state=me,this.loadedmetadata||(this.startFragRequested=!1,this.nextLoadPosition=this.startPosition),this.tick()},h.onBufferFlushed=function(){var e=this.mediaBuffer?this.mediaBuffer:this.media;if(e){var t=this.audioOnly?p.AUDIO:p.VIDEO;this.fragmentTracker.detectEvictedFragments(t,e.buffered)}this.state=me,this.fragPrevious=null},h.onLevelsUpdated=function(e){this.levels=e.levels},h.swapAudioCodec=function(){this.audioCodecSwap=!this.audioCodecSwap},h._seekToStartPos=function(){var e=this.media,t=this.startPosition,r=e.currentTime;if(r!==t&&t>=0){if(e.seeking)return void d.b.log("could not seek to "+t+", already seeking at "+r);d.b.log("seek to target start position "+t+" from current time "+r+". ready state "+e.readyState),e.currentTime=t}},h._getAudioCodec=function(e){var t=this.config.defaultAudioCodec||e.audioCodec;return this.audioCodecSwap&&(d.b.log("swapping playlist audio codec"),t&&(t=-1!==t.indexOf("mp4a.40.5")?"mp4a.40.2":"mp4a.40.5")),t},a=i,(s=[{key:"state",set:function(e){if(this.state!==e){var t=this.state;this._state=e,d.b.log("main stream-controller: "+t+"->"+e),this.hls.trigger(u.a.STREAM_STATE_TRANSITION,{previousState:t,nextState:e})}},get:function(){return this._state}},{key:"currentLevel",get:function(){var e=this.media;if(e){var t=this.getBufferedFrag(e.currentTime);if(t)return t.level}return-1}},{key:"nextBufferedFrag",get:function(){var e=this.media;return e?this.followingBufferedFrag(this.getBufferedFrag(e.currentTime)):null}},{key:"nextLevel",get:function(){var e=this.nextBufferedFrag;return e?e.level:-1}},{key:"liveSyncPosition",get:function(){return this._liveSyncPosition},set:function(e){this._liveSyncPosition=e}}])&&Ce(a.prototype,s),c&&Ce(a,c),i}(Oe);function xe(e,t){for(var r=0;r0){t=r[0].bitrate,r.sort((function(e,t){return e.bitrate-t.bitrate})),this._levels=r;for(var c=0;c=0&&e1&&c.loadError0){var t=this.currentLevelIndex,r=e.urlId,i=e.url[r];d.b.log("Attempt loading level index "+t+" with URL-id "+r),this.hls.trigger(u.a.LEVEL_LOADING,{url:i,level:t,id:r})}}},l.removeLevel=function(e,t){var r=this.levels.filter((function(r,i){return i!==e||r.url.length>1&&void 0!==t&&(r.url=r.url.filter((function(e,r){return r!==t})),r.urlId=0,!0)})).map((function(e,t){var r=e.details;return r&&r.fragments&&r.fragments.forEach((function(e){e.level=t})),e}));this._levels=r,this.hls.trigger(u.a.LEVELS_UPDATED,{levels:r})},a=i,(n=[{key:"levels",get:function(){return this._levels}},{key:"level",get:function(){return this.currentLevelIndex},set:function(e){var t=this._levels;t&&(e=Math.min(e,t.length-1),this.currentLevelIndex===e&&t[e].details||this.setLevelInternal(e))}},{key:"manualLevel",get:function(){return this.manualLevelIndex},set:function(e){this.manualLevelIndex=e,void 0===this._startLevel&&(this._startLevel=e),-1!==e&&(this.level=e)}},{key:"firstLevel",get:function(){return this._firstLevel},set:function(e){this._firstLevel=e}},{key:"startLevel",get:function(){if(void 0===this._startLevel){var e=this.hls.config.startLevel;return void 0!==e?e:this._firstLevel}return this._startLevel},set:function(e){this._startLevel=e}},{key:"nextLoadLevel",get:function(){return-1!==this.manualLevelIndex?this.manualLevelIndex:this.hls.nextAutoLevel},set:function(e){this.level=e,-1===this.manualLevelIndex&&(this.hls.nextAutoLevel=e)}}])&&xe(a.prototype,n),s&&xe(a,s),i}(h),Fe=r(4);function Ue(e,t){var r;try{r=new Event("addtrack")}catch(e){(r=document.createEvent("Event")).initEvent("addtrack",!1,!1)}r.track=e,t.dispatchEvent(r)}function Ne(e){if(null==e?void 0:e.cues)for(;e.cues.length>0;)e.removeCue(e.cues[0])}var Be=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.MEDIA_ATTACHED,u.a.MEDIA_DETACHING,u.a.FRAG_PARSING_METADATA,u.a.LIVE_BACK_BUFFER_REACHED)||this).id3Track=void 0,r.media=void 0,r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){h.prototype.destroy.call(this)},a.onMediaAttached=function(e){this.media=e.media,this.media},a.onMediaDetaching=function(){Ne(this.id3Track),this.id3Track=void 0,this.media=void 0},a.getID3Track=function(e){for(var t=0;to&&(d.b.warn("detected an id3 sample with endTime < startTime, adjusting endTime to (startTime + 0.25)"),o=s+.25);for(var l=0;le[e.length-1].endTime)return e[e.length-1];for(var r=0,i=e.length-1;r<=i;){var a=Math.floor((i+r)/2);if(te[a].endTime))return e[a];r=a+1}}return e[r].endTime-t=this.minWeight_},t.getEstimate=function(){return this.canEstimate()?Math.min(this.fast_.getEstimate(),this.slow_.getEstimate()):this.defaultEstimate_},t.destroy=function(){},e}();function je(e,t){for(var r=0;r500*r.duration/s){var o=e.levels,l=Math.max(1,a.bw?a.bw/8:1e3*a.loaded/n),c=o[r.level];if(!c)return;var h=c.realBitrate?Math.max(c.realBitrate,c.bitrate):c.bitrate,f=a.total?a.total:Math.max(a.loaded,Math.round(r.duration*h/8)),g=t.currentTime,p=(f-a.loaded)/l,v=(H.bufferInfo(t,g,e.config.maxBufferHole).end-g)/s;if(v<2*r.duration/s&&p>v){var m,y=e.minAutoLevel;for(m=r.level-1;m>y;m--){var b=o[m].realBitrate?Math.max(o[m].realBitrate,o[m].bitrate):o[m].bitrate;if(r.duration*b/(6.4*l)=i;u--){var c=l[u];if(c){var h=c.details,f=h?h.totalduration/h.fragments.length:t,g=!!h&&h.live,p=void 0;p=u<=e?s*r:o*r;var v=l[u].realBitrate?Math.max(l[u].realBitrate,l[u].bitrate):l[u].bitrate,m=v*f/p;if(d.b.trace("level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: "+u+"/"+Math.round(p)+"/"+v+"/"+f+"/"+n+"/"+m),p>v&&(!m||g&&!this.bitrateTestDelay||m=0)return f;d.b.trace("rebuffering expected to happen, lets try to find a quality level minimizing the rebuffering");var g=o?Math.min(o,i.maxStarvationDelay):i.maxStarvationDelay,p=i.abrBandWidthFactor,v=i.abrBandWidthUpFactor;if(0===h){var m=this.bitrateTestDelay;m&&(g=(o?Math.min(o,i.maxLoadingDelay):i.maxLoadingDelay)-m,d.b.trace("bitrate test took "+Math.round(1e3*m)+"ms, set first fragment max fetchDuration to "+Math.round(1e3*g)+" ms"),p=v=1)}return f=this._findBestLevel(s,o,c,a,t,h+g,p,v,r),Math.max(f,0)}}])&&je(a.prototype,n),s&&je(a,s),i}(h);var Ye=q(),We=function(e){var t,r;function i(t){var r;return(r=e.call(this,t,u.a.MEDIA_ATTACHING,u.a.MEDIA_DETACHING,u.a.MANIFEST_PARSED,u.a.BUFFER_RESET,u.a.BUFFER_APPENDING,u.a.BUFFER_CODECS,u.a.BUFFER_EOS,u.a.BUFFER_FLUSHING,u.a.LEVEL_PTS_UPDATED,u.a.LEVEL_UPDATED)||this)._msDuration=null,r._levelDuration=null,r._levelTargetDuration=10,r._live=null,r._objectUrl=null,r._needsFlush=!1,r._needsEos=!1,r.config=void 0,r.audioTimestampOffset=void 0,r.bufferCodecEventsExpected=0,r._bufferCodecEventsTotal=0,r.media=null,r.mediaSource=null,r.segments=[],r.parent=void 0,r.appending=!1,r.appended=0,r.appendError=0,r.flushBufferCounter=0,r.tracks={},r.pendingTracks={},r.sourceBuffer={},r.flushRange=[],r._onMediaSourceOpen=function(){d.b.log("media source opened"),r.hls.trigger(u.a.MEDIA_ATTACHED,{media:r.media});var e=r.mediaSource;e&&e.removeEventListener("sourceopen",r._onMediaSourceOpen),r.checkPendingTracks()},r._onMediaSourceClose=function(){d.b.log("media source closed")},r._onMediaSourceEnded=function(){d.b.log("media source ended")},r._onSBUpdateEnd=function(){if(r.audioTimestampOffset&&r.sourceBuffer.audio){var e=r.sourceBuffer.audio;d.b.warn("change mpeg audio timestamp offset from "+e.timestampOffset+" to "+r.audioTimestampOffset),e.timestampOffset=r.audioTimestampOffset,delete r.audioTimestampOffset}r._needsFlush&&r.doFlush(),r._needsEos&&r.checkEos(),r.appending=!1;var t=r.parent,i=r.segments.reduce((function(e,r){return r.parent===t?e+1:e}),0),a={},n=r.sourceBuffer;for(var s in n){var o=n[s];if(!o)throw Error("handling source buffer update end error: source buffer for "+s+" uninitilized and unable to update buffered TimeRanges.");a[s]=o.buffered}r.hls.trigger(u.a.BUFFER_APPENDED,{parent:t,pending:i,timeRanges:a}),r._needsFlush||r.doAppending(),r.updateMediaElementDuration(),0===i&&r.flushLiveBackBuffer()},r._onSBUpdateError=function(e){d.b.error("sourceBuffer error:",e),r.hls.trigger(u.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_APPENDING_ERROR,fatal:!1})},r.config=t.config,r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){h.prototype.destroy.call(this)},a.onLevelPtsUpdated=function(e){var t=e.type,r=this.tracks.audio;if("audio"===t&&r&&"audio/mpeg"===r.container){var i=this.sourceBuffer.audio;if(!i)throw Error("Level PTS Updated and source buffer for audio uninitalized");if(Math.abs(i.timestampOffset-e.start)>.1){var a=i.updating;try{i.abort()}catch(e){d.b.warn("can not abort audio buffer: "+e)}a?this.audioTimestampOffset=e.start:(d.b.warn("change mpeg audio timestamp offset from "+i.timestampOffset+" to "+e.start),i.timestampOffset=e.start)}}},a.onManifestParsed=function(e){var t=2;(e.audio&&!e.video||!e.altAudio)&&(t=1),this.bufferCodecEventsExpected=this._bufferCodecEventsTotal=t,d.b.log(this.bufferCodecEventsExpected+" bufferCodec event(s) expected")},a.onMediaAttaching=function(e){var t=this.media=e.media;if(t&&Ye){var r=this.mediaSource=new Ye;r.addEventListener("sourceopen",this._onMediaSourceOpen),r.addEventListener("sourceended",this._onMediaSourceEnded),r.addEventListener("sourceclose",this._onMediaSourceClose),t.src=window.URL.createObjectURL(r),this._objectUrl=t.src}},a.onMediaDetaching=function(){d.b.log("media source detaching");var e=this.mediaSource;if(e){if("open"===e.readyState)try{e.endOfStream()}catch(e){d.b.warn("onMediaDetaching:"+e.message+" while calling endOfStream")}e.removeEventListener("sourceopen",this._onMediaSourceOpen),e.removeEventListener("sourceended",this._onMediaSourceEnded),e.removeEventListener("sourceclose",this._onMediaSourceClose),this.media&&(this._objectUrl&&window.URL.revokeObjectURL(this._objectUrl),this.media.src===this._objectUrl?(this.media.removeAttribute("src"),this.media.load()):d.b.warn("media.src was changed by a third party - skip cleanup")),this.mediaSource=null,this.media=null,this._objectUrl=null,this.bufferCodecEventsExpected=this._bufferCodecEventsTotal,this.pendingTracks={},this.tracks={},this.sourceBuffer={},this.flushRange=[],this.segments=[],this.appended=0}this.hls.trigger(u.a.MEDIA_DETACHED)},a.checkPendingTracks=function(){var e=this.bufferCodecEventsExpected,t=this.pendingTracks,r=Object.keys(t).length;(r&&!e||2===r)&&(this.createSourceBuffers(t),this.pendingTracks={},this.doAppending())},a.onBufferReset=function(){var e=this.sourceBuffer;for(var t in e){var r=e[t];try{r&&(this.mediaSource&&this.mediaSource.removeSourceBuffer(r),r.removeEventListener("updateend",this._onSBUpdateEnd),r.removeEventListener("error",this._onSBUpdateError))}catch(e){}}this.sourceBuffer={},this.flushRange=[],this.segments=[],this.appended=0},a.onBufferCodecs=function(e){var t=this;Object.keys(this.sourceBuffer).length||(Object.keys(e).forEach((function(r){t.pendingTracks[r]=e[r]})),this.bufferCodecEventsExpected=Math.max(this.bufferCodecEventsExpected-1,0),this.mediaSource&&"open"===this.mediaSource.readyState&&this.checkPendingTracks())},a.createSourceBuffers=function(e){var t=this.sourceBuffer,r=this.mediaSource;if(!r)throw Error("createSourceBuffers called when mediaSource was null");for(var i in e)if(!t[i]){var a=e[i];if(!a)throw Error("source buffer exists for track "+i+", however track does not");var n=a.levelCodec||a.codec,s=a.container+";codecs="+n;d.b.log("creating sourceBuffer("+s+")");try{var l=t[i]=r.addSourceBuffer(s);l.addEventListener("updateend",this._onSBUpdateEnd),l.addEventListener("error",this._onSBUpdateError),this.tracks[i]={buffer:l,codec:n,id:a.id,container:a.container,levelCodec:a.levelCodec}}catch(e){d.b.error("error while trying to add sourceBuffer:"+e.message),this.hls.trigger(u.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.BUFFER_ADD_CODEC_ERROR,fatal:!1,err:e,mimeType:s})}}this.hls.trigger(u.a.BUFFER_CREATED,{tracks:this.tracks})},a.onBufferAppending=function(e){this._needsFlush||(this.segments?this.segments.push(e):this.segments=[e],this.doAppending())},a.onBufferEos=function(e){for(var t in this.sourceBuffer)if(!e.type||e.type===t){var r=this.sourceBuffer[t];r&&!r.ended&&(r.ended=!0,d.b.log(t+" sourceBuffer now EOS"))}this.checkEos()},a.checkEos=function(){var e=this.sourceBuffer,t=this.mediaSource;if(t&&"open"===t.readyState){for(var r in e){var i=e[r];if(i){if(!i.ended)return;if(i.updating)return void(this._needsEos=!0)}}d.b.log("all media data are available, signal endOfStream() to MediaSource and stop loading fragment");try{t.endOfStream()}catch(e){d.b.warn("exception while calling mediaSource.endOfStream()")}this._needsEos=!1}else this._needsEos=!1},a.onBufferFlushing=function(e){e.type?this.flushRange.push({start:e.startOffset,end:e.endOffset,type:e.type}):(this.flushRange.push({start:e.startOffset,end:e.endOffset,type:"video"}),this.flushRange.push({start:e.startOffset,end:e.endOffset,type:"audio"})),this.flushBufferCounter=0,this.doFlush()},a.flushLiveBackBuffer=function(){if(this._live){var e=this.config.liveBackBufferLength;if(isFinite(e)&&!(e<0))if(this.media)for(var t=this.media.currentTime,r=this.sourceBuffer,i=Object.keys(r),a=t-Math.max(e,this._levelTargetDuration),n=i.length-1;n>=0;n--){var s=i[n],o=r[s];if(o){var l=o.buffered;l.length>0&&a>l.start(0)&&this.removeBufferRange(s,o,0,a)&&this.hls.trigger(u.a.LIVE_BACK_BUFFER_REACHED,{bufferEnd:a})}}else d.b.error("flushLiveBackBuffer called without attaching media")}},a.onLevelUpdated=function(e){var t=e.details;t.fragments.length>0&&(this._levelDuration=t.totalduration+t.fragments[0].start,this._levelTargetDuration=t.averagetargetduration||t.targetduration||10,this._live=t.live,this.updateMediaElementDuration())},a.updateMediaElementDuration=function(){var e,t=this.config;if(null!==this._levelDuration&&this.media&&this.mediaSource&&this.sourceBuffer&&0!==this.media.readyState&&"open"===this.mediaSource.readyState){for(var r in this.sourceBuffer){var i=this.sourceBuffer[r];if(i&&!0===i.updating)return}e=this.media.duration,null===this._msDuration&&(this._msDuration=this.mediaSource.duration),!0===this._live&&!0===t.liveDurationInfinity?(d.b.log("Media Source duration is set to Infinity"),this._msDuration=this.mediaSource.duration=1/0):(this._levelDuration>this._msDuration&&this._levelDuration>e||!Object(l.a)(e))&&(d.b.log("Updating Media Source duration to "+this._levelDuration.toFixed(3)),this._msDuration=this.mediaSource.duration=this._levelDuration)}},a.doFlush=function(){for(;this.flushRange.length;){var e=this.flushRange[0];if(!this.flushBuffer(e.start,e.end,e.type))return void(this._needsFlush=!0);this.flushRange.shift(),this.flushBufferCounter=0}if(0===this.flushRange.length){this._needsFlush=!1;var t=0,r=this.sourceBuffer;try{for(var i in r){var a=r[i];a&&(t+=a.buffered.length)}}catch(e){d.b.error("error while accessing sourceBuffer.buffered")}this.appended=t,this.hls.trigger(u.a.BUFFER_FLUSHED)}},a.doAppending=function(){var e=this.config,t=this.hls,r=this.segments,i=this.sourceBuffer;if(Object.keys(i).length){if(!this.media||this.media.error)return this.segments=[],void d.b.error("trying to append although a media error occured, flush segment and abort");if(!this.appending){var a=r.shift();if(a)try{var n=i[a.type];if(!n)return void this._onSBUpdateEnd();if(n.updating)return void r.unshift(a);n.ended=!1,this.parent=a.parent,n.appendBuffer(a.data),this.appendError=0,this.appended++,this.appending=!0}catch(i){d.b.error("error while trying to append buffer:"+i.message),r.unshift(a);var s={type:o.b.MEDIA_ERROR,parent:a.parent,details:"",fatal:!1};22===i.code?(this.segments=[],s.details=o.a.BUFFER_FULL_ERROR):(this.appendError++,s.details=o.a.BUFFER_APPEND_ERROR,this.appendError>e.appendErrorMaxRetry&&(d.b.log("fail "+e.appendErrorMaxRetry+" times to append segment in sourceBuffer"),this.segments=[],s.fatal=!0)),t.trigger(u.a.ERROR,s)}}}},a.flushBuffer=function(e,t,r){var i=this.sourceBuffer;if(!Object.keys(i).length)return!0;var a="null";if(this.media&&(a=this.media.currentTime.toFixed(3)),d.b.log("flushBuffer,pos/start/end: "+a+"/"+e+"/"+t),this.flushBufferCounter>=this.appended)return d.b.warn("abort flushing too many retries"),!0;var n=i[r];if(n){if(n.ended=!1,n.updating)return d.b.warn("cannot flush, sb updating in progress"),!1;if(this.removeBufferRange(r,n,e,t))return this.flushBufferCounter++,!1}return d.b.log("buffer flushed"),!0},a.removeBufferRange=function(e,t,r,i){try{for(var a=0;a.5){var u="null";return this.media&&(u=this.media.currentTime.toString()),d.b.log("sb remove "+e+" ["+o+","+l+"], of ["+n+","+s+"], pos:"+u),t.remove(o,l),!0}}}catch(e){d.b.warn("removeBufferRange failed",e)}return!1},i}(h);function qe(e,t){for(var r=0;rthis.autoLevelCapping&&t.streamController.nextLevelSwitch(),this.autoLevelCapping=t.autoLevelCapping}}},o.getMaxLevel=function(e){var t=this;if(!this.levels)return-1;var r=this.levels.filter((function(r,a){return i.isLevelAllowed(a,t.restrictedLevels)&&a<=e}));return this.clientRect=null,i.getMaxLevelByMediaSize(r,this.mediaWidth,this.mediaHeight)},o.startCapping=function(){this.timer||(this.autoLevelCapping=Number.POSITIVE_INFINITY,this.hls.firstLevel=this.getMaxLevel(this.firstLevel),clearInterval(this.timer),this.timer=setInterval(this.detectPlayerSize.bind(this),1e3),this.detectPlayerSize())},o.stopCapping=function(){this.restrictedLevels=[],this.firstLevel=null,this.autoLevelCapping=Number.POSITIVE_INFINITY,this.timer&&(this.timer=clearInterval(this.timer),this.timer=null)},o.getDimensions=function(){if(this.clientRect)return this.clientRect;var e=this.media,t={width:0,height:0};if(e){var r=e.getBoundingClientRect();t.width=r.width,t.height=r.height,t.width||t.height||(t.width=r.right-r.left||e.width||0,t.height=r.bottom-r.top||e.height||0)}return this.clientRect=t,t},i.isLevelAllowed=function(e,t){return void 0===t&&(t=[]),-1===t.indexOf(e)},i.getMaxLevelByMediaSize=function(e,t,r){if(!e||e&&!e.length)return-1;for(var i,a,n=e.length-1,s=0;s=t||o.height>=r)&&(i=o,!(a=e[s+1])||i.width!==a.width||i.height!==a.height)){n=s;break}}return n},a=i,s=[{key:"contentScaleFactor",get:function(){var e=1;try{e=window.devicePixelRatio}catch(e){}return e}}],(n=[{key:"mediaWidth",get:function(){return this.getDimensions().width*i.contentScaleFactor}},{key:"mediaHeight",get:function(){return this.getDimensions().height*i.contentScaleFactor}}])&&qe(a.prototype,n),s&&qe(a,s),i}(h);var ze=window.performance,Qe=function(e){var t,r;function i(t){return e.call(this,t,u.a.MEDIA_ATTACHING)||this}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.destroy=function(){this.timer&&clearInterval(this.timer),this.isVideoPlaybackQualityAvailable=!1},a.onMediaAttaching=function(e){var t=this.hls.config;t.capLevelOnFPSDrop&&("function"==typeof(this.video=e.media instanceof window.HTMLVideoElement?e.media:null).getVideoPlaybackQuality&&(this.isVideoPlaybackQualityAvailable=!0),clearInterval(this.timer),this.timer=setInterval(this.checkFPSInterval.bind(this),t.fpsDroppedMonitoringPeriod))},a.checkFPS=function(e,t,r){var i=ze.now();if(t){if(this.lastTime){var a=i-this.lastTime,n=r-this.lastDroppedFrames,s=t-this.lastDecodedFrames,o=1e3*n/a,l=this.hls;if(l.trigger(u.a.FPS_DROP,{currentDropped:n,currentDecoded:s,totalDroppedFrames:r}),o>0&&n>l.config.fpsDroppedMonitoringThreshold*s){var c=l.currentLevel;d.b.warn("drop FPS ratio greater than max allowed value for currentLevel: "+c),c>0&&(-1===l.autoLevelCapping||l.autoLevelCapping>=c)&&(c-=1,l.trigger(u.a.FPS_DROP_LEVEL_CAPPING,{level:c,droppedLevel:l.currentLevel}),l.autoLevelCapping=c,l.streamController.nextLevelSwitch())}}this.lastTime=i,this.lastDroppedFrames=r,this.lastDecodedFrames=t}},a.checkFPSInterval=function(){var e=this.video;if(e)if(this.isVideoPlaybackQualityAvailable){var t=e.getVideoPlaybackQuality();this.checkFPS(e,t.totalVideoFrames,t.droppedVideoFrames)}else this.checkFPS(e,e.webkitDecodedFrameCount,e.webkitDroppedFrameCount)},i}(h),$e=function(){function e(e){e&&e.xhrSetup&&(this.xhrSetup=e.xhrSetup)}var t=e.prototype;return t.destroy=function(){this.abort(),this.loader=null},t.abort=function(){var e=this.loader;e&&4!==e.readyState&&(this.stats.aborted=!0,e.abort()),window.clearTimeout(this.requestTimeout),this.requestTimeout=null,window.clearTimeout(this.retryTimeout),this.retryTimeout=null},t.load=function(e,t,r){this.context=e,this.config=t,this.callbacks=r,this.stats={trequest:window.performance.now(),retry:0},this.retryDelay=t.retryDelay,this.loadInternal()},t.loadInternal=function(){var e,t=this.context;e=this.loader=new window.XMLHttpRequest;var r=this.stats;r.tfirst=0,r.loaded=0;var i=this.xhrSetup;try{if(i)try{i(e,t.url)}catch(r){e.open("GET",t.url,!0),i(e,t.url)}e.readyState||e.open("GET",t.url,!0)}catch(r){return void this.callbacks.onError({code:e.status,text:r.message},t,e)}t.rangeEnd&&e.setRequestHeader("Range","bytes="+t.rangeStart+"-"+(t.rangeEnd-1)),e.onreadystatechange=this.readystatechange.bind(this),e.onprogress=this.loadprogress.bind(this),e.responseType=t.responseType,this.requestTimeout=window.setTimeout(this.loadtimeout.bind(this),this.config.timeout),e.send()},t.readystatechange=function(e){var t=e.currentTarget,r=t.readyState,i=this.stats,a=this.context,n=this.config;if(!i.aborted&&r>=2)if(window.clearTimeout(this.requestTimeout),0===i.tfirst&&(i.tfirst=Math.max(window.performance.now(),i.trequest)),4===r){var s=t.status;if(s>=200&&s<300){var o,l;i.tload=Math.max(i.tfirst,window.performance.now()),l="arraybuffer"===a.responseType?(o=t.response).byteLength:(o=t.responseText).length,i.loaded=i.total=l;var u={url:t.responseURL,data:o};this.callbacks.onSuccess(u,i,a,t)}else i.retry>=n.maxRetry||s>=400&&s<499?(d.b.error(s+" while loading "+a.url),this.callbacks.onError({code:s,text:t.statusText},a,t)):(d.b.warn(s+" while loading "+a.url+", retrying in "+this.retryDelay+"..."),this.destroy(),this.retryTimeout=window.setTimeout(this.loadInternal.bind(this),this.retryDelay),this.retryDelay=Math.min(2*this.retryDelay,n.maxRetryDelay),i.retry++)}else this.requestTimeout=window.setTimeout(this.loadtimeout.bind(this),n.timeout)},t.loadtimeout=function(){d.b.warn("timeout while loading "+this.context.url),this.callbacks.onTimeout(this.stats,this.context,null)},t.loadprogress=function(e){var t=e.currentTarget,r=this.stats;r.loaded=e.loaded,e.lengthComputable&&(r.total=e.total);var i=this.callbacks.onProgress;i&&i(r,this.context,null,t)},e}();function Je(e,t){for(var r=0;r=this.tracks.length)d.b.warn("Invalid audio track id:",e.id);else{if(d.b.log("audioTrack "+e.id+" loaded"),this.tracks[e.id].details=e.details,e.details.live&&!this.hasInterval()){var t=1e3*e.details.targetduration;this.setInterval(t)}!e.details.live&&this.hasInterval()&&this.clearInterval()}},l.onAudioTrackSwitched=function(e){var t=this.tracks[e.id].groupId;t&&this.audioGroupId!==t&&(this.audioGroupId=t)},l.onLevelLoaded=function(e){this._selectAudioGroup(e.level)},l.onError=function(e){e.type===o.b.NETWORK_ERROR&&(e.fatal&&this.clearInterval(),e.details===o.a.AUDIO_TRACK_LOAD_ERROR&&(d.b.warn("Network failure on audio-track id:",e.context.id),this._handleLoadError()))},l._setAudioTrack=function(e){if(this._trackId===e&&this.tracks[this._trackId].details)d.b.debug("Same id as current audio-track passed, and track details available -> no-op");else if(e<0||e>=this.tracks.length)d.b.warn("Invalid id passed to audio-track controller");else{var t=this.tracks[e];d.b.log("Now switching to audio-track index "+e),this.clearInterval(),this._trackId=e;var r=t.url,i=t.type,a=t.id;this.hls.trigger(u.a.AUDIO_TRACK_SWITCHING,{id:a,type:i,url:r}),this._loadTrackDetailsIfNeeded(t)}},l.doTick=function(){this._updateTrack(this._trackId)},l._selectAudioGroup=function(e){var t=this.hls.levels[e];if(t&&t.audioGroupIds){var r=t.audioGroupIds[t.urlId];this.audioGroupId!==r&&(this.audioGroupId=r,this._selectInitialAudioTrack())}},l._selectInitialAudioTrack=function(){var e=this,t=this.tracks;if(t.length){var r=this.tracks[this._trackId],i=null;if(r&&(i=r.name),this._selectDefaultTrack){var a=t.filter((function(e){return e.default}));a.length?t=a:d.b.warn("No default audio tracks defined")}var n=!1,s=function(){t.forEach((function(t){n||e.audioGroupId&&t.groupId!==e.audioGroupId||i&&i!==t.name||(e._setAudioTrack(t.id),n=!0)}))};s(),n||(i=null,s()),n||(d.b.error("No track found for running audio group-ID: "+this.audioGroupId),this.hls.trigger(u.a.ERROR,{type:o.b.MEDIA_ERROR,details:o.a.AUDIO_TRACK_LOAD_ERROR,fatal:!0}))}},l._needsTrackLoading=function(e){var t=e.details,r=e.url;return!(t&&!t.live)&&!!r},l._loadTrackDetailsIfNeeded=function(e){if(this._needsTrackLoading(e)){var t=e.url,r=e.id;d.b.log("loading audio-track playlist for id: "+r),this.hls.trigger(u.a.AUDIO_TRACK_LOADING,{url:t,id:r})}},l._updateTrack=function(e){if(!(e<0||e>=this.tracks.length)){this.clearInterval(),this._trackId=e,d.b.log("trying to update audio-track "+e);var t=this.tracks[e];this._loadTrackDetailsIfNeeded(t)}},l._handleLoadError=function(){this.trackIdBlacklist[this._trackId]=!0;var e=this._trackId,t=this.tracks[e],r=t.name,i=t.language,a=t.groupId;d.b.warn("Loading failed on audio track id: "+e+", group-id: "+a+', name/language: "'+r+'" / "'+i+'"');for(var n=e,s=0;s0&&-1===e?(d.b.log("audio:override startPosition with lastCurrentTime @"+t.toFixed(3)),this.state=me):(this.lastCurrentTime=this.startPosition?this.startPosition:e,this.state=ve),this.nextLoadPosition=this.startPosition=this.lastCurrentTime,this.tick()}else this.startPosition=e,this.state=pe},c.doTick=function(){var e,t,r,i=this.hls,a=i.config;switch(this.state){case we:case ye:case Ae:break;case ve:this.state=Se,this.loadedmetadata=!1;break;case me:var n=this.tracks;if(!n)break;if(!this.media&&(this.startFragRequested||!a.startFragPrefetch))break;if(this.loadedmetadata)e=this.media.currentTime;else if(void 0===(e=this.nextLoadPosition))break;var s=this.mediaBuffer?this.mediaBuffer:this.media,o=this.videoBuffer?this.videoBuffer:this.media,c=eR||h.nextStart))return;d.b.log("alt audio track ahead of main track, seek to start of alt audio track"),this.media.currentTime=R+.05}if(r.initSegment&&!r.initSegment.data)E=r.initSegment;else if(p<=R){if(E=S[0],null!==this.videoTrackCC&&E.cc!==this.videoTrackCC&&(E=function(e,t){return j.search(e,(function(e){return e.cct?-1:0}))}(S,this.videoTrackCC)),r.live&&E.loadIdx&&E.loadIdx===this.fragLoadIdx){var k=h.nextStart?h.nextStart:R;return d.b.log("no alt audio available @currentTime:"+this.media.currentTime+", seeking @"+(k+.05)),void(this.media.currentTime=k+.05)}}else{var w,L=a.maxFragLookUpTolerance,D=v?S[v.sn-S[0].sn+1]:void 0,O=function(e){var t=Math.min(L,e.duration);return e.start+e.duration-t<=p?1:e.start-t>p&&e.start?-1:0};pA-L&&(L=0),w=D&&!O(D)?D:j.search(S,O)):w=S[_-1],w&&(E=w,R=w.start,v&&E.level===v.level&&E.sn===v.sn&&(E.sn=I||P)&&(d.b.log("audioStreamController: retryDate reached, switch back to IDLE state"),this.state=me);break;case Le:var x=this.videoTrackCC;if(void 0===this.initPTS[x])break;var M=this.waitingFragment;if(M){var F=M.frag.cc;x!==F?(t=this.tracks[this.trackId]).details&&t.details.live&&(d.b.warn("Waiting fragment CC ("+F+") does not match video track CC ("+x+")"),this.waitingFragment=null,this.state=me):(this.state=Te,this.onFragLoaded(this.waitingFragment),this.waitingFragment=null)}else this.state=me}},c.onMediaAttached=function(e){var t=this.media=this.mediaBuffer=e.media;this.onvseeking=this.onMediaSeeking.bind(this),this.onvended=this.onMediaEnded.bind(this),t.addEventListener("seeking",this.onvseeking),t.addEventListener("ended",this.onvended);var r=this.config;this.tracks&&r.autoStartLoad&&this.startLoad(r.startPosition)},c.onMediaDetaching=function(){var e=this.media;e&&e.ended&&(d.b.log("MSE detaching and video ended, reset startPosition"),this.startPosition=this.lastCurrentTime=0),e&&(e.removeEventListener("seeking",this.onvseeking),e.removeEventListener("ended",this.onvended),this.onvseeking=this.onvseeked=this.onvended=null),this.media=this.mediaBuffer=this.videoBuffer=null,this.loadedmetadata=!1,this.fragmentTracker.removeAllFragments(),this.stopLoad()},c.onAudioTracksUpdated=function(e){d.b.log("audio tracks updated"),this.tracks=e.audioTracks},c.onAudioTrackSwitching=function(e){var t=!!e.url;this.trackId=e.id,this.fragCurrent=null,this.state=ye,this.waitingFragment=null,t?this.setInterval(100):this.demuxer&&(this.demuxer.destroy(),this.demuxer=null),t&&(this.audioSwitch=!0,this.state=me),this.tick()},c.onAudioTrackLoaded=function(e){var t=e.details,r=e.id,i=this.tracks[r],a=t.totalduration,n=0;if(d.b.log("track "+r+" loaded ["+t.startSN+","+t.endSN+"],duration:"+a),t.live){var s=i.details;s&&t.fragments.length>0?(re(s,t),n=t.fragments[0].start,t.PTSKnown?d.b.log("live audio playlist sliding:"+n.toFixed(3)):d.b.log("live audio playlist - outdated PTS, unknown sliding")):(t.PTSKnown=!1,d.b.log("live audio playlist - first load, unknown sliding"))}else t.PTSKnown=!1;if(i.details=t,!this.startFragRequested){if(-1===this.startPosition){var o=t.startTimeOffset;Object(l.a)(o)?(d.b.log("start time offset found in playlist, adjust startPosition to "+o),this.startPosition=o):t.live?(this.startPosition=this.computeLivePosition(n,t),d.b.log("compute startPosition for audio-track to "+this.startPosition)):this.startPosition=0}this.nextLoadPosition=this.startPosition}this.state===Se&&(this.state=me),this.tick()},c.onKeyLoaded=function(){this.state===be&&(this.state=me,this.tick())},c.onFragLoaded=function(e){var t=this.fragCurrent,r=e.frag;if(this.state===Te&&t&&"audio"===r.type&&r.level===t.level&&r.sn===t.sn){var i=this.tracks[this.trackId],a=i.details,n=a.totalduration,s=t.level,o=t.sn,l=t.cc,c=this.config.defaultAudioCodec||i.audioCodec||"mp4a.40.2",h=this.stats=e.stats;if("initSegment"===o)this.state=me,h.tparsed=h.tbuffered=tt.now(),a.initSegment.data=e.payload,this.hls.trigger(u.a.FRAG_BUFFERED,{stats:h,frag:t,id:"audio"}),this.tick();else{this.state=_e,this.appended=!1,this.demuxer||(this.demuxer=new J(this.hls,"audio"));var f=this.initPTS[l],g=a.initSegment?a.initSegment.data:[];if(a.initSegment||void 0!==f){this.pendingBuffering=!0,d.b.log("Demuxing "+o+" of ["+a.startSN+" ,"+a.endSN+"],track "+s);this.demuxer.push(e.payload,g,c,null,t,n,!1,f)}else d.b.log("unknown video PTS for continuity counter "+l+", waiting for video PTS before demuxing audio frag "+o+" of ["+a.startSN+" ,"+a.endSN+"],track "+s),this.waitingFragment=e,this.state=Le}}this.fragLoadError=0},c.onFragParsingInitSegment=function(e){var t=this.fragCurrent,r=e.frag;if(t&&"audio"===e.id&&r.sn===t.sn&&r.level===t.level&&this.state===_e){var i,a=e.tracks;if(a.video&&delete a.video,i=a.audio){i.levelCodec=i.codec,i.id=e.id,this.hls.trigger(u.a.BUFFER_CODECS,a),d.b.log("audio track:audio,container:"+i.container+",codecs[level/parsed]=["+i.levelCodec+"/"+i.codec+"]");var n=i.initSegment;if(n){var s={type:"audio",data:n,parent:"audio",content:"initSegment"};this.audioSwitch?this.pendingData=[s]:(this.appended=!0,this.pendingBuffering=!0,this.hls.trigger(u.a.BUFFER_APPENDING,s))}this.tick()}}},c.onFragParsingData=function(e){var t=this,r=this.fragCurrent,i=e.frag;if(r&&"audio"===e.id&&"audio"===e.type&&i.sn===r.sn&&i.level===r.level&&this.state===_e){var a=this.trackId,n=this.tracks[a],s=this.hls;Object(l.a)(e.endPTS)||(e.endPTS=e.startPTS+r.duration,e.endDTS=e.startDTS+r.duration),r.addElementaryStream(p.AUDIO),d.b.log("parsed "+e.type+",PTS:["+e.startPTS.toFixed(3)+","+e.endPTS.toFixed(3)+"],DTS:["+e.startDTS.toFixed(3)+"/"+e.endDTS.toFixed(3)+"],nb:"+e.nb),te(n.details,r,e.startPTS,e.endPTS);var c=this.audioSwitch,h=this.media,f=!1;if(c)if(h&&h.readyState){var g=h.currentTime;d.b.log("switching audio track : currentTime:"+g),g>=e.startPTS&&(d.b.log("switching audio track : flushing all audio"),this.state=Ae,s.trigger(u.a.BUFFER_FLUSHING,{startOffset:0,endOffset:Number.POSITIVE_INFINITY,type:"audio"}),f=!0,this.audioSwitch=!1,s.trigger(u.a.AUDIO_TRACK_SWITCHED,{id:a}))}else this.audioSwitch=!1,s.trigger(u.a.AUDIO_TRACK_SWITCHED,{id:a});var v=this.pendingData;if(!v)return d.b.warn("Apparently attempt to enqueue media payload without codec initialization data upfront"),void s.trigger(u.a.ERROR,{type:o.b.MEDIA_ERROR,details:null,fatal:!0});this.audioSwitch||([e.data1,e.data2].forEach((function(t){t&&t.length&&v.push({type:e.type,data:t,parent:"audio",content:"data"})})),!f&&v.length&&(v.forEach((function(e){t.state===_e&&(t.pendingBuffering=!0,t.hls.trigger(u.a.BUFFER_APPENDING,e))})),this.pendingData=[],this.appended=!0)),this.tick()}},c.onFragParsed=function(e){var t=this.fragCurrent,r=e.frag;t&&"audio"===e.id&&r.sn===t.sn&&r.level===t.level&&this.state===_e&&(this.stats.tparsed=tt.now(),this.state=Re,this._checkAppendedParsed())},c.onBufferReset=function(){this.mediaBuffer=this.videoBuffer=null,this.loadedmetadata=!1},c.onBufferCreated=function(e){var t=e.tracks.audio;t&&(this.mediaBuffer=t.buffer,this.loadedmetadata=!0),e.tracks.video&&(this.videoBuffer=e.tracks.video.buffer)},c.onBufferAppended=function(e){if("audio"===e.parent){var t=this.state;t!==_e&&t!==Re||(this.pendingBuffering=e.pending>0,this._checkAppendedParsed())}},c._checkAppendedParsed=function(){if(!(this.state!==Re||this.appended&&this.pendingBuffering)){var e=this.fragCurrent,t=this.stats,r=this.hls;if(e){this.fragPrevious=e,t.tbuffered=tt.now(),r.trigger(u.a.FRAG_BUFFERED,{stats:t,frag:e,id:"audio"});var i=this.mediaBuffer?this.mediaBuffer:this.media;i&&d.b.log("audio buffered : "+ne.toString(i.buffered)),this.audioSwitch&&this.appended&&(this.audioSwitch=!1,r.trigger(u.a.AUDIO_TRACK_SWITCHED,{id:this.trackId})),this.state=me}this.tick()}},c.onError=function(e){var t=e.frag;if(!t||"audio"===t.type)switch(e.details){case o.a.FRAG_LOAD_ERROR:case o.a.FRAG_LOAD_TIMEOUT:var r=e.frag;if(r&&"audio"!==r.type)break;if(!e.fatal){var i=this.fragLoadError;i?i++:i=1;var a=this.config;if(i<=a.fragLoadingMaxRetry){this.fragLoadError=i;var n=Math.min(Math.pow(2,i-1)*a.fragLoadingRetryDelay,a.fragLoadingMaxRetryTimeout);d.b.warn("AudioStreamController: frag loading failed, retry in "+n+" ms"),this.retryDate=tt.now()+n,this.state=Ee}else d.b.error("AudioStreamController: "+e.details+" reaches max retry, redispatch as fatal ..."),e.fatal=!0,this.state=we}break;case o.a.AUDIO_TRACK_LOAD_ERROR:case o.a.AUDIO_TRACK_LOAD_TIMEOUT:case o.a.KEY_LOAD_ERROR:case o.a.KEY_LOAD_TIMEOUT:this.state!==we&&(this.state=e.fatal?we:me,d.b.warn("AudioStreamController: "+e.details+" while loading frag, now switching to "+this.state+" state ..."));break;case o.a.BUFFER_FULL_ERROR:if("audio"===e.parent&&(this.state===_e||this.state===Re)){var s=this.mediaBuffer,l=this.media.currentTime;if(s&&H.isBuffered(s,l)&&H.isBuffered(s,l+.5)){var c=this.config;c.maxMaxBufferLength>=c.maxBufferLength&&(c.maxMaxBufferLength/=2,d.b.warn("AudioStreamController: reduce max buffer length to "+c.maxMaxBufferLength+"s")),this.state=me}else d.b.warn("AudioStreamController: buffer full error also media.currentTime is not buffered, flush audio buffer"),this.fragCurrent=null,this.state=Ae,this.hls.trigger(u.a.BUFFER_FLUSHING,{startOffset:0,endOffset:Number.POSITIVE_INFINITY,type:"audio"})}}},c.onBufferFlushed=function(){var e=this,t=this.pendingData;t&&t.length?(d.b.log("AudioStreamController: appending pending audio data after buffer flushed"),t.forEach((function(t){e.hls.trigger(u.a.BUFFER_APPENDING,t)})),this.appended=!0,this.pendingData=[],this.state=Re):(this.state=me,this.fragPrevious=null,this.tick())},a=i,(n=[{key:"state",set:function(e){if(this.state!==e){var t=this.state;this._state=e,d.b.log("audio stream:"+t+"->"+e)}},get:function(){return this._state}}])&&et(a.prototype,n),s&&et(a,s),i}(Oe),it=function(){if("undefined"!=typeof window&&window.VTTCue)return window.VTTCue;var e={"":!0,lr:!0,rl:!0},t={start:!0,middle:!0,end:!0,left:!0,right:!0};function r(e){return"string"==typeof e&&(!!t[e.toLowerCase()]&&e.toLowerCase())}function i(e){for(var t=1;t100)throw new Error("Position must be between 0 and 100.");y=e,this.hasBeenReset=!0}})),Object.defineProperty(s,"positionAlign",i({},o,{get:function(){return b},set:function(e){var t=r(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");b=t,this.hasBeenReset=!0}})),Object.defineProperty(s,"size",i({},o,{get:function(){return T},set:function(e){if(e<0||e>100)throw new Error("Size must be between 0 and 100.");T=e,this.hasBeenReset=!0}})),Object.defineProperty(s,"align",i({},o,{get:function(){return E},set:function(e){var t=r(e);if(!t)throw new SyntaxError("An invalid or illegal string was specified.");E=t,this.hasBeenReset=!0}})),s.displayState=void 0}return a.prototype.getCueAsHTML=function(){return window.WebVTT.convertCueToDOMTree(window,this.text)},a}(),at=function(){return{decode:function(e){if(!e)return"";if("string"!=typeof e)throw new Error("Error - expected string data.");return decodeURIComponent(encodeURIComponent(e))}}};function nt(){this.window=window,this.state="INITIAL",this.buffer="",this.decoder=new at,this.regionList=[]}function st(){this.values=Object.create(null)}function ot(e,t,r,i){var a=i?e.split(i):[e];for(var n in a)if("string"==typeof a[n]){var s=a[n].split(r);if(2===s.length)t(s[0],s[1])}}st.prototype={set:function(e,t){this.get(e)||""===t||(this.values[e]=t)},get:function(e,t,r){return r?this.has(e)?this.values[e]:t[r]:this.has(e)?this.values[e]:t},has:function(e){return e in this.values},alt:function(e,t,r){for(var i=0;i=0&&t<=100)&&(this.set(e,t),!0)}};var lt=new it(0,0,0),ut="middle"===lt.align?"middle":"center";function dt(e,t,r){var i=e;function a(){var t=function(e){function t(e,t,r,i){return 3600*(0|e)+60*(0|t)+(0|r)+(0|i)/1e3}var r=e.match(/^(\d+):(\d{2})(:\d{2})?\.(\d{3})/);return r?r[3]?t(r[1],r[2],r[3].replace(":",""),r[4]):r[1]>59?t(r[1],r[2],0,r[4]):t(0,r[1],r[2],r[4]):null}(e);if(null===t)throw new Error("Malformed timestamp: "+i);return e=e.replace(/^[^\sa-zA-Z-]+/,""),t}function n(){e=e.replace(/^\s+/,"")}if(n(),t.startTime=a(),n(),"--\x3e"!==e.substr(0,3))throw new Error("Malformed time stamp (time stamps must be separated by '--\x3e'): "+i);e=e.substr(3),n(),t.endTime=a(),n(),function(e,t){var i=new st;ot(e,(function(e,t){switch(e){case"region":for(var a=r.length-1;a>=0;a--)if(r[a].id===t){i.set(e,r[a].region);break}break;case"vertical":i.alt(e,t,["rl","lr"]);break;case"line":var n=t.split(","),s=n[0];i.integer(e,s),i.percent(e,s)&&i.set("snapToLines",!1),i.alt(e,s,["auto"]),2===n.length&&i.alt("lineAlign",n[1],["start",ut,"end"]);break;case"position":n=t.split(","),i.percent(e,n[0]),2===n.length&&i.alt("positionAlign",n[1],["start",ut,"end","line-left","line-right","auto"]);break;case"size":i.percent(e,t);break;case"align":i.alt(e,t,["start",ut,"end","left","right"])}}),/:/,/\s/),t.region=i.get("region",null),t.vertical=i.get("vertical","");var a=i.get("line","auto");"auto"===a&&-1===lt.line&&(a=-1),t.line=a,t.lineAlign=i.get("lineAlign","start"),t.snapToLines=i.get("snapToLines",!0),t.size=i.get("size",100),t.align=i.get("align",ut);var n=i.get("position","auto");"auto"===n&&50===lt.position&&(n="start"===t.align||"left"===t.align?0:"end"===t.align||"right"===t.align?100:50),t.position=n}(e,t)}function ct(e){return e.replace(//gi,"\n")}nt.prototype={parse:function(e){var t=this;function r(){var e=t.buffer,r=0;for(e=ct(e);r=16?o--:o++,navigator.userAgent.match(/Firefox\//)?n.line=c+1:n.line=c>7?c-2:c+1,n.align="left",n.position=Math.max(0,Math.min(100,o/32*100)),u.push(n),e&&e.addCue(n)}return u}var gt,pt={42:225,92:233,94:237,95:243,96:250,123:231,124:247,125:209,126:241,127:9608,128:174,129:176,130:189,131:191,132:8482,133:162,134:163,135:9834,136:224,137:32,138:232,139:226,140:234,141:238,142:244,143:251,144:193,145:201,146:211,147:218,148:220,149:252,150:8216,151:161,152:42,153:8217,154:9473,155:169,156:8480,157:8226,158:8220,159:8221,160:192,161:194,162:199,163:200,164:202,165:203,166:235,167:206,168:207,169:239,170:212,171:217,172:249,173:219,174:171,175:187,176:195,177:227,178:205,179:204,180:236,181:210,182:242,183:213,184:245,185:123,186:125,187:92,188:94,189:95,190:124,191:8764,192:196,193:228,194:214,195:246,196:223,197:165,198:164,199:9475,200:197,201:229,202:216,203:248,204:9487,205:9491,206:9495,207:9499},vt=function(e){var t=e;return pt.hasOwnProperty(e)&&(t=pt[e]),String.fromCharCode(t)},mt={17:1,18:3,21:5,22:7,23:9,16:11,19:12,20:14},yt={17:2,18:4,21:6,22:8,23:10,19:13,20:15},bt={25:1,26:3,29:5,30:7,31:9,24:11,27:12,28:14},Tt={25:2,26:4,29:6,30:8,31:10,27:13,28:15},Et=["white","green","blue","cyan","red","yellow","magenta","black","transparent"];!function(e){e[e.ERROR=0]="ERROR",e[e.TEXT=1]="TEXT",e[e.WARNING=2]="WARNING",e[e.INFO=2]="INFO",e[e.DEBUG=3]="DEBUG",e[e.DATA=3]="DATA"}(gt||(gt={}));var St=function(){function e(){this.time=null,this.verboseLevel=gt.ERROR}return e.prototype.log=function(e,t){this.verboseLevel>=e&&d.b.log(this.time+" ["+e+"] "+t)},e}(),_t=function(e){for(var t=[],r=0;r100&&(this.logger.log(gt.DEBUG,"Too large cursor position "+this.pos),this.pos=100)},t.moveCursor=function(e){var t=this.pos+e;if(e>1)for(var r=this.pos+1;r=144&&this.backSpace();var t=vt(e);this.pos>=100?this.logger.log(gt.ERROR,"Cannot insert "+e.toString(16)+" ("+t+") at position "+this.pos+". Skipping it!"):(this.chars[this.pos].setChar(t,this.currPenState),this.moveCursor(1))},t.clearFromPos=function(e){var t;for(t=e;t<100;t++)this.chars[t].reset()},t.clear=function(){this.clearFromPos(0),this.pos=0,this.currPenState.reset()},t.clearToEndOfRow=function(){this.clearFromPos(this.pos)},t.getTextString=function(){for(var e=[],t=!0,r=0;r<100;r++){var i=this.chars[r].uchar;" "!==i&&(t=!1),e.push(i)}return t?"":e.join("")},t.setPenStyles=function(e){this.currPenState.setStyles(e),this.chars[this.pos].setPenState(this.currPenState)},e}(),wt=function(){function e(e){this.rows=void 0,this.currRow=void 0,this.nrRollUpRows=void 0,this.lastOutputScreen=void 0,this.logger=void 0,this.rows=[];for(var t=0;t<15;t++)this.rows.push(new kt(e));this.logger=e,this.currRow=14,this.nrRollUpRows=null,this.lastOutputScreen=null,this.reset()}var t=e.prototype;return t.reset=function(){for(var e=0;e<15;e++)this.rows[e].clear();this.currRow=14},t.equals=function(e){for(var t=!0,r=0;r<15;r++)if(!this.rows[r].equals(e.rows[r])){t=!1;break}return t},t.copy=function(e){for(var t=0;t<15;t++)this.rows[t].copy(e.rows[t])},t.isEmpty=function(){for(var e=!0,t=0;t<15;t++)if(!this.rows[t].isEmpty()){e=!1;break}return e},t.backSpace=function(){this.rows[this.currRow].backSpace()},t.clearToEndOfRow=function(){this.rows[this.currRow].clearToEndOfRow()},t.insertChar=function(e){this.rows[this.currRow].insertChar(e)},t.setPen=function(e){this.rows[this.currRow].setPenStyles(e)},t.moveCursor=function(e){this.rows[this.currRow].moveCursor(e)},t.setCursor=function(e){this.logger.log(gt.INFO,"setCursor: "+e),this.rows[this.currRow].setCursor(e)},t.setPAC=function(e){this.logger.log(gt.INFO,"pacData = "+JSON.stringify(e));var t=e.row-1;if(this.nrRollUpRows&&t0&&(r=e?"["+t.join(" | ")+"]":t.join("\n")),r},t.getTextAndFormat=function(){return this.rows},e}(),Lt=function(){function e(e,t,r){this.chNr=void 0,this.outputFilter=void 0,this.mode=void 0,this.verbose=void 0,this.displayedMemory=void 0,this.nonDisplayedMemory=void 0,this.lastOutputScreen=void 0,this.currRollUpRow=void 0,this.writeScreen=void 0,this.cueStartTime=void 0,this.logger=void 0,this.chNr=e,this.outputFilter=t,this.mode=null,this.verbose=0,this.displayedMemory=new wt(r),this.nonDisplayedMemory=new wt(r),this.lastOutputScreen=new wt(r),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null,this.logger=r}var t=e.prototype;return t.reset=function(){this.mode=null,this.displayedMemory.reset(),this.nonDisplayedMemory.reset(),this.lastOutputScreen.reset(),this.outputFilter.reset(),this.currRollUpRow=this.displayedMemory.rows[14],this.writeScreen=this.displayedMemory,this.mode=null,this.cueStartTime=null},t.getHandler=function(){return this.outputFilter},t.setHandler=function(e){this.outputFilter=e},t.setPAC=function(e){this.writeScreen.setPAC(e)},t.setBkgData=function(e){this.writeScreen.setBkgData(e)},t.setMode=function(e){e!==this.mode&&(this.mode=e,this.logger.log(gt.INFO,"MODE="+e),"MODE_POP-ON"===this.mode?this.writeScreen=this.nonDisplayedMemory:(this.writeScreen=this.displayedMemory,this.writeScreen.reset()),"MODE_ROLL-UP"!==this.mode&&(this.displayedMemory.nrRollUpRows=null,this.nonDisplayedMemory.nrRollUpRows=null),this.mode=e)},t.insertChars=function(e){for(var t=0;t=46,t.italics)t.foreground="white";else{var r=Math.floor(e/2)-16;t.foreground=["white","green","blue","cyan","red","yellow","magenta"][r]}this.logger.log(gt.INFO,"MIDROW: "+JSON.stringify(t)),this.writeScreen.setPen(t)},t.outputDataUpdate=function(e){void 0===e&&(e=!1);var t=this.logger.time;null!==t&&this.outputFilter&&(null!==this.cueStartTime||this.displayedMemory.isEmpty()?this.displayedMemory.equals(this.lastOutputScreen)||(this.outputFilter.newCue(this.cueStartTime,t,this.lastOutputScreen),e&&this.outputFilter.dispatchCue&&this.outputFilter.dispatchCue(),this.cueStartTime=this.displayedMemory.isEmpty()?null:t):this.cueStartTime=t,this.lastOutputScreen.copy(this.displayedMemory))},t.cueSplitAtTime=function(e){this.outputFilter&&(this.displayedMemory.isEmpty()||(this.outputFilter.newCue&&this.outputFilter.newCue(this.cueStartTime,e,this.displayedMemory),this.cueStartTime=e))},e}();function Dt(e,t,r){r.a=e,r.b=t}function Ot(e,t,r){return r.a===e&&r.b===t}var Ct=function(){function e(e,t,r){this.channels=void 0,this.currentChannel=0,this.cmdHistory=void 0,this.logger=void 0;var i=new St;this.channels=[null,new Lt(e,t,i),new Lt(e+1,r,i)],this.cmdHistory={a:null,b:null},this.logger=i}var t=e.prototype;return t.getHandler=function(e){return this.channels[e].getHandler()},t.setHandler=function(e,t){this.channels[e].setHandler(t)},t.addData=function(e,t){var r,i,a,n=!1;this.logger.time=e;for(var s=0;s ("+_t([i,a])+")"),(r=this.parseCmd(i,a))||(r=this.parseMidrow(i,a)),r||(r=this.parsePAC(i,a)),r||(r=this.parseBackgroundAttributes(i,a)),!r&&(n=this.parseChars(i,a))){var o=this.currentChannel;if(o&&o>0)this.channels[o].insertChars(n);else this.logger.log(gt.WARNING,"No channel found yet. TEXT-MODE?")}r||n||this.logger.log(gt.WARNING,"Couldn't parse cleaned data "+_t([i,a])+" orig: "+_t([t[s],t[s+1]]))}},t.parseCmd=function(e,t){var r=this.cmdHistory;if(!((20===e||28===e||21===e||29===e)&&t>=32&&t<=47)&&!((23===e||31===e)&&t>=33&&t<=35))return!1;if(Ot(e,t,r))return Dt(null,null,r),this.logger.log(gt.DEBUG,"Repeated command ("+_t([e,t])+") is dropped"),!0;var i=20===e||21===e||23===e?1:2,a=this.channels[i];return 20===e||21===e||28===e||29===e?32===t?a.ccRCL():33===t?a.ccBS():34===t?a.ccAOF():35===t?a.ccAON():36===t?a.ccDER():37===t?a.ccRU(2):38===t?a.ccRU(3):39===t?a.ccRU(4):40===t?a.ccFON():41===t?a.ccRDC():42===t?a.ccTR():43===t?a.ccRTD():44===t?a.ccEDM():45===t?a.ccCR():46===t?a.ccENM():47===t&&a.ccEOC():a.ccTO(t-32),Dt(e,t,r),this.currentChannel=i,!0},t.parseMidrow=function(e,t){var r=0;if((17===e||25===e)&&t>=32&&t<=47){if((r=17===e?1:2)!==this.currentChannel)return this.logger.log(gt.ERROR,"Mismatch channel in midrow parsing"),!1;var i=this.channels[r];return!!i&&(i.ccMIDROW(t),this.logger.log(gt.DEBUG,"MIDROW ("+_t([e,t])+")"),!0)}return!1},t.parsePAC=function(e,t){var r,i=this.cmdHistory;if(!((e>=17&&e<=23||e>=25&&e<=31)&&t>=64&&t<=127)&&!((16===e||24===e)&&t>=64&&t<=95))return!1;if(Ot(e,t,i))return Dt(null,null,i),!0;var a=e<=23?1:2;r=t>=64&&t<=95?1===a?mt[e]:bt[e]:1===a?yt[e]:Tt[e];var n=this.channels[a];return!!n&&(n.setPAC(this.interpretPAC(r,t)),Dt(e,t,i),this.currentChannel=a,!0)},t.interpretPAC=function(e,t){var r=t,i={color:null,italics:!1,indent:null,underline:!1,row:e};return r=t>95?t-96:t-64,i.underline=1==(1&r),r<=13?i.color=["white","green","blue","cyan","red","yellow","magenta","white"][Math.floor(r/2)]:r<=15?(i.italics=!0,i.color="white"):i.indent=4*Math.floor((r-16)/2),i},t.parseChars=function(e,t){var r,i=null,a=null;if(e>=25?(r=2,a=e-8):(r=1,a=e),a>=17&&a<=19){var n=t;n=17===a?t+80:18===a?t+112:t+144,this.logger.log(gt.INFO,"Special char '"+vt(n)+"' in channel "+r),i=[n]}else e>=32&&e<=127&&(i=0===t?[e]:[e,t]);if(i){var s=_t(i);this.logger.log(gt.DEBUG,"Char codes = "+s.join(",")),Dt(e,t,this.cmdHistory)}return i},t.parseBackgroundAttributes=function(e,t){var r;if(!((16===e||24===e)&&t>=32&&t<=47)&&!((23===e||31===e)&&t>=45&&t<=47))return!1;var i={};16===e||24===e?(r=Math.floor((t-32)/2),i.background=Et[r],t%2==1&&(i.background=i.background+"_semi")):45===t?i.background="transparent":(i.foreground="black",47===t&&(i.underline=!0));var a=e<=23?1:2;return this.channels[a].setBkgData(i),Dt(e,t,this.cmdHistory),!0},t.reset=function(){for(var e=0;ee)&&(this.startTime=e),this.endTime=t,this.screen=r,this.timelineController.createCaptionsTrack(this.trackName)},t.reset=function(){this.cueRanges=[]},e}(),Pt=function(e,t,r){return e.substr(r||0,t.length)===t},xt=function(e){for(var t=5381,r=e.length;r;)t=33*t^e.charCodeAt(--r);return(t>>>0).toString()},Mt={parse:function(e,t,r,i,a,n){var s,o=Object(Fe.b)(new Uint8Array(e)).trim().replace(/\r\n|\n\r|\n|\r/g,"\n").split("\n"),u="00:00.000",d=0,c=0,h=0,f=[],g=!0,p=!1,v=new ht;v.oncue=function(e){var t=r[i],a=r.ccOffset;t&&t.new&&(void 0!==c?a=r.ccOffset=t.start:function(e,t,r){var i=e[t],a=e[i.prevCC];if(!a||!a.new&&i.new)return e.ccOffset=e.presentationOffset=i.start,void(i.new=!1);for(;a&&a.new;)e.ccOffset+=i.start-a.start,i.new=!1,a=e[(i=a).prevCC];e.presentationOffset=r}(r,i,h)),h&&(a=h-r.presentationOffset),p&&(e.startTime+=a-c,e.endTime+=a-c),e.id=xt(e.startTime.toString())+xt(e.endTime.toString())+xt(e.text),e.text=decodeURIComponent(encodeURIComponent(e.text)),e.endTime>0&&f.push(e)},v.onparsingerror=function(e){s=e},v.onflush=function(){s&&n?n(s):a(f)},o.forEach((function(e){if(g){if(Pt(e,"X-TIMESTAMP-MAP=")){g=!1,p=!0,e.substr(16).split(",").forEach((function(e){Pt(e,"LOCAL:")?u=e.substr(6):Pt(e,"MPEGTS:")&&(d=parseInt(e.substr(7)))}));try{t+(9e4*r[i].start||0)<0&&(t+=8589934592),d-=t,c=function(e){var t=parseInt(e.substr(-3)),r=parseInt(e.substr(-6,2)),i=parseInt(e.substr(-9,2)),a=e.length>9?parseInt(e.substr(0,e.indexOf(":"))):0;if(!(Object(l.a)(t)&&Object(l.a)(r)&&Object(l.a)(i)&&Object(l.a)(a)))throw Error("Malformed X-TIMESTAMP-MAP: Local:"+e);return t+=1e3*r,t+=6e4*i,t+=36e5*a}(u)/1e3,h=d/9e4}catch(e){p=!1,s=e}return}""===e&&(g=!1)}v.parse(e+"\n")})),v.flush()}};function Ft(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function Ut(e,t){return e&&e.label===t.name&&!(e.textTrack1||e.textTrack2)}var Nt=function(e){var t,r;function i(t){var r;if((r=e.call(this,t,u.a.MEDIA_ATTACHING,u.a.MEDIA_DETACHING,u.a.FRAG_PARSING_USERDATA,u.a.FRAG_DECRYPTED,u.a.MANIFEST_LOADING,u.a.MANIFEST_LOADED,u.a.FRAG_LOADED,u.a.INIT_PTS_FOUND)||this).media=null,r.config=void 0,r.enabled=!0,r.Cues=void 0,r.textTracks=[],r.tracks=[],r.initPTS=[],r.unparsedVttFrags=[],r.captionsTracks={},r.nonNativeCaptionsTracks={},r.captionsProperties=void 0,r.cea608Parser1=void 0,r.cea608Parser2=void 0,r.lastSn=-1,r.prevCC=-1,r.vttCCs={ccOffset:0,presentationOffset:0,0:{start:0,prevCC:-1,new:!1}},r.hls=t,r.config=t.config,r.Cues=t.config.cueHandler,r.captionsProperties={textTrack1:{label:r.config.captionsTextTrack1Label,languageCode:r.config.captionsTextTrack1LanguageCode},textTrack2:{label:r.config.captionsTextTrack2Label,languageCode:r.config.captionsTextTrack2LanguageCode},textTrack3:{label:r.config.captionsTextTrack3Label,languageCode:r.config.captionsTextTrack3LanguageCode},textTrack4:{label:r.config.captionsTextTrack4Label,languageCode:r.config.captionsTextTrack4LanguageCode}},r.config.enableCEA708Captions){var i=new It(Ft(r),"textTrack1"),a=new It(Ft(r),"textTrack2"),n=new It(Ft(r),"textTrack3"),s=new It(Ft(r),"textTrack4");r.cea608Parser1=new Ct(1,i,a),r.cea608Parser2=new Ct(3,n,s)}return r}r=e,(t=i).prototype=Object.create(r.prototype),t.prototype.constructor=t,t.__proto__=r;var a=i.prototype;return a.addCues=function(e,t,r,i,a){for(var n,s,o,l,d=!1,c=a.length;c--;){var h=a[c],f=(n=h[0],s=h[1],o=t,l=r,Math.min(s,l)-Math.max(n,o));if(f>=0&&(h[0]=Math.min(h[0],t),h[1]=Math.max(h[1],r),d=!0,f/(r-t)>.5))return}if(d||a.push([t,r]),this.config.renderTextTracksNatively)this.Cues.newCue(this.captionsTracks[e],t,r,i);else{var g=this.Cues.newCue(null,t,r,i);this.hls.trigger(u.a.CUES_PARSED,{type:"captions",cues:g,track:e})}},a.onInitPtsFound=function(e){var t=this,r=e.frag,i=e.id,a=e.initPTS,n=this.unparsedVttFrags;"main"===i&&(this.initPTS[r.cc]=a),n.length&&(this.unparsedVttFrags=[],n.forEach((function(e){t.onFragLoaded(e)})))},a.getExistingTrack=function(e){var t=this.media;if(t)for(var r=0;r=n.length||r!==a||!s||this.stopped)this._clearReloadTimer();else if(d.b.log("subtitle track "+r+" loaded"),i.live){var o=ae(s.details,i,e.stats.trequest);d.b.log("Reloading live subtitle playlist in "+o+"ms"),this.timer=setTimeout((function(){t._loadCurrentTrack()}),o)}else this._clearReloadTimer()},o.startLoad=function(){this.stopped=!1,this._loadCurrentTrack()},o.stopLoad=function(){this.stopped=!0,this._clearReloadTimer()},o._clearReloadTimer=function(){this.timer&&(clearTimeout(this.timer),this.timer=null)},o._loadCurrentTrack=function(){var e=this.trackId,t=this.tracks,r=this.hls,i=t[e];e<0||!i||i.details&&!i.details.live||(d.b.log("Loading subtitle track "+e),r.trigger(u.a.SUBTITLE_TRACK_LOADING,{url:i.url,id:e}))},o._toggleTrackModes=function(e){var t=this.media,r=this.subtitleDisplay,i=this.trackId;if(t){var a=Gt(t.textTracks);if(-1===e)[].slice.call(a).forEach((function(e){e.mode="disabled"}));else{var n=a[i];n&&(n.mode="disabled")}var s=a[e];s&&(s.mode=r?"showing":"hidden")}},o._setSubtitleTrackInternal=function(e){var t=this.hls,r=this.tracks;!Object(l.a)(e)||e<-1||e>=r.length||(this.trackId=e,d.b.log("Switching to subtitle track "+e),t.trigger(u.a.SUBTITLE_TRACK_SWITCH,{id:e}),this._loadCurrentTrack())},o._onTextTracksChanged=function(){if(this.media&&this.hls.config.renderTextTracksNatively){for(var e=-1,t=Gt(this.media.textTracks),r=0;r=i[s].start&&n<=i[s].end){a=i[s];break}var o=t.start+t.duration;a?a.end=o:(a={start:n,end:o},i.push(a))}}},a.onMediaAttached=function(e){var t=e.media;this.media=t,t.addEventListener("seeking",this._onMediaSeeking),this.state=me},a.onMediaDetaching=function(){var e=this;this.media&&(this.media.removeEventListener("seeking",this._onMediaSeeking),this.fragmentTracker.removeAllFragments(),this.currentTrackId=-1,this.tracks.forEach((function(t){e.tracksBuffered[t.id]=[]})),this.media=null,this.state=pe)},a.onError=function(e){var t=e.frag;t&&"subtitle"===t.type&&(this.state=me)},a.onSubtitleTracksUpdated=function(e){var t=this;d.b.log("subtitle tracks updated"),this.tracksBuffered=[],this.tracks=e.subtitleTracks,this.tracks.forEach((function(e){t.tracksBuffered[e.id]=[]}))},a.onSubtitleTrackSwitch=function(e){if(this.currentTrackId=e.id,this.tracks&&this.tracks.length&&-1!==this.currentTrackId){var t=this.tracks[this.currentTrackId];t&&t.details&&this.setInterval(500)}else this.clearInterval()},a.onSubtitleTrackLoaded=function(e){var t=e.id,r=e.details,i=this.currentTrackId,a=this.tracks,n=a[i];t>=a.length||t!==i||!n||(r.live&&function(e,t,r){void 0===r&&(r=0);var i=-1;ie(e,t,(function(e,t,r){t.start=e.start,i=r}));var a=t.fragments;if(i<0)a.forEach((function(e){e.start+=r}));else for(var n=i+1;n0&&r&&r.key&&"AES-128"===r.method){var n=Vt.now();this.decrypter.decrypt(e.payload,r.key.buffer,r.iv.buffer,(function(e){var t=Vt.now();a.trigger(u.a.FRAG_DECRYPTED,{frag:i,payload:e,stats:{tstart:n,tdecrypt:t}})}))}},a.onLevelUpdated=function(e){var t=e.details.fragments;this.lastAVStart=t.length?t[0].start:0},a.doTick=function(){if(this.media)switch(this.state){case me:var e=this.config,t=this.currentTrackId,r=this.fragmentTracker,i=this.media,a=this.tracks;if(!a||!a[t]||!a[t].details)break;var n,s=e.maxBufferHole,o=e.maxFragLookUpTolerance,l=Math.min(e.maxBufferLength,e.maxMaxBufferLength),c=H.bufferedInfo(this._getBuffered(),i.currentTime,s),h=c.end,f=c.len,g=a[t].details,p=g.fragments,v=p.length,m=p[v-1].start+p[v-1].duration;if(f>l)return;var y=this.fragPrevious;h3)return void this.hls.trigger(u.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0});var a=3-this._requestLicenseFailureCount+1;d.b.warn("Retrying license request, "+a+" attempts left"),this._requestLicense(r,i)}}},l._generateLicenseRequestChallenge=function(e,t){switch(e.mediaKeySystemDomain){case Ht.WIDEVINE:return t}throw new Error("unsupported key-system: "+e.mediaKeySystemDomain)},l._requestLicense=function(e,t){d.b.log("Requesting content license for key-system");var r=this._mediaKeysList[0];if(!r)return d.b.error("Fatal error: Media is encrypted but no key-system access has been obtained yet"),void this.hls.trigger(u.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_NO_ACCESS,fatal:!0});try{var i=this.getLicenseServerUrl(r.mediaKeySystemDomain),a=this._createLicenseXhr(i,e,t);d.b.log("Sending license request to URL: "+i);var n=this._generateLicenseRequestChallenge(r,e);a.send(n)}catch(e){d.b.error("Failure requesting DRM license: "+e),this.hls.trigger(u.a.ERROR,{type:o.b.KEY_SYSTEM_ERROR,details:o.a.KEY_SYSTEM_LICENSE_REQUEST_FAILED,fatal:!0})}},l.onMediaAttached=function(e){if(this._emeEnabled){var t=e.media;this._media=t,t.addEventListener("encrypted",this._onMediaEncrypted)}},l.onMediaDetached=function(){var e=this._media,t=this._mediaKeysList;e&&(e.removeEventListener("encrypted",this._onMediaEncrypted),this._media=null,this._mediaKeysList=[],Promise.all(t.map((function(e){if(e.mediaKeysSession)return e.mediaKeysSession.close().catch((function(){}))}))).then((function(){return e.setMediaKeys(null)})).catch((function(){})))},l.onManifestParsed=function(e){if(this._emeEnabled){var t=e.levels.map((function(e){return e.audioCodec})),r=e.levels.map((function(e){return e.videoCodec}));this._attemptKeySystemAccess(Ht.WIDEVINE,t,r)}},a=i,(n=[{key:"requestMediaKeySystemAccess",get:function(){if(!this._requestMediaKeySystemAccess)throw new Error("No requestMediaKeySystemAccess function configured");return this._requestMediaKeySystemAccess}}])&&qt(a.prototype,n),s&&qt(a,s),i}(h);function zt(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);t&&(i=i.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,i)}return r}function Qt(e){for(var t=1;tt)return i}return 0}},{key:"maxAutoLevel",get:function(){var e=this.levels,t=this.autoLevelCapping;return-1===t&&e&&e.length?e.length-1:t}},{key:"nextAutoLevel",get:function(){return Math.min(Math.max(this.abrController.nextAutoLevel,this.minAutoLevel),this.maxAutoLevel)},set:function(e){this.abrController.nextAutoLevel=Math.max(this.minAutoLevel,e)}},{key:"audioTracks",get:function(){var e=this.audioTrackController;return e?e.audioTracks:[]}},{key:"audioTrack",get:function(){var e=this.audioTrackController;return e?e.audioTrack:-1},set:function(e){var t=this.audioTrackController;t&&(t.audioTrack=e)}},{key:"liveSyncPosition",get:function(){return this.streamController.liveSyncPosition}},{key:"subtitleTracks",get:function(){var e=this.subtitleTrackController;return e?e.subtitleTracks:[]}},{key:"subtitleTrack",get:function(){var e=this.subtitleTrackController;return e?e.subtitleTrack:-1},set:function(e){var t=this.subtitleTrackController;t&&(t.subtitleTrack=e)}},{key:"subtitleDisplay",get:function(){var e=this.subtitleTrackController;return!!e&&e.subtitleDisplay},set:function(e){var t=this.subtitleTrackController;t&&(t.subtitleDisplay=e)}}]),i}(z);nr.defaultConfig=void 0}]).default})); +//# sourceMappingURL=hls.min.js.map diff --git a/resources/assets/js/jwplayer-8.9.3.js b/resources/assets/js/jwplayer-8.9.3.js new file mode 100644 index 0000000..0c338e5 --- /dev/null +++ b/resources/assets/js/jwplayer-8.9.3.js @@ -0,0 +1,13 @@ +(function() { +if(!window.jwplayer){ +/*! + JW Player version 8.9.3 + Copyright (c) 2019, JW Player, All Rights Reserved + This source code and its use and distribution is subject to the terms + and conditions of the applicable license agreement. + https://www.jwplayer.com/tos/ + This product includes portions of other software. For the full text of licenses, see + https://ssl.p.jwpcdn.com/player/v/8.9.3/notice.txt +*/ +window.jwplayer=function(t){function e(e){for(var n,i,o=e[0],u=e[1],a=0,s=[];a2;if(null==t&&(t=[]),p&&t.reduce===p)return r&&(e=G(e,r)),i?t.reduce(e,n):t.reduce(e);if(k(t,function(t,o,u){i?n=e.call(r,n,t,o,u):(n=t,i=!0)}),!i)throw new TypeError("Reduce of empty array with no initial value");return n},E=S,T=S,A=function(t,e,n){var r;return L(t,function(t,i,o){if(e.call(n,t,i,o))return r=t,!0}),r},_=A,F=function(t,e,n){var r=[];return null==t?r:v&&t.filter===v?t.filter(e,n):(k(t,function(t,i,o){e.call(n,t,i,o)&&r.push(t)}),r)},I=F,M=function(t,e,n){e||(e=Ct);var r=!0;return null==t?r:g&&t.every===g?t.every(e,n):(k(t,function(t,o,u){if(!(r=r&&e.call(n,t,o,u)))return i}),!!r)},N=M,L=function(t,e,n){e||(e=Ct);var r=!1;return null==t?r:b&&t.some===b?t.some(e,n):(k(t,function(t,o,u){if(r||(r=e.call(n,t,o,u)))return i}),!!r)},D=L,R=function(t){return null==t?0:t.length===+t.length?t.length:ot(t).length},B=function(t,e){var n;return function(){return--t>0&&(n=e.apply(this,arguments)),t<=1&&(e=null),n}},q=function(t){return null==t?Ct:gt(t)?t:xt(t)},z=function(t){return function(e,n,r){var i={};return n=q(n),k(e,function(o,u){var a=n.call(r,o,u,e);t(i,a,o)}),i}},V=z(function(t,e,n){kt(t,e)?t[e].push(n):t[e]=[n]}),Q=z(function(t,e,n){t[e]=n}),W=function(t,e,n,r){for(var i=(n=q(n)).call(r,e),o=0,u=t.length;o>>1;n.call(r,t[a])=0)},U=X,H=function(t,e){return F(t,St(e))},Y=function(t,e){return A(t,St(e))},K=function(t){var e=s.apply(o,c.call(arguments,1));return F(t,function(t){return!X(e,t)})},J=function(t,e,n){if(null==t)return-1;var r=0,i=t.length;if(n){if("number"!=typeof n)return t[r=W(t,e)]===e?r:-1;r=n<0?Math.max(0,i+n):n}if(m&&t.indexOf===m)return t.indexOf(e,n);for(;r1&&void 0!==arguments[1]?arguments[1]:100;return function(){for(var r=this,i=arguments.length,o=new Array(i),u=0;ui&&(r=t,i=a)}),r},memoize:et,now:Et,omit:function(t){var e={},n=s.apply(o,c.call(arguments,1));for(var r in t)X(n,r)||(e[r]=t[r]);return e},once:tt,partial:Z,pick:lt,pluck:function(t,e){return P(t,xt(e))},property:xt,propertyOf:function(t){return null==t?function(){}:function(e){return t[e]}},reduce:S,reject:function(t,e,n){return F(t,function(t,r,i){return!e.call(n,t,r,i)},n)},result:function(t,e){if(null!=t){var n=t[e];return gt(n)?n.call(t):n}},select:I,size:R,some:D,sortedIndex:W,throttle:it,where:H,without:function(t){return K(t,c.call(arguments,1))}}},function(t,e,n){"use strict";n.d(e,"y",function(){return o}),n.d(e,"x",function(){return u}),n.d(e,"w",function(){return a}),n.d(e,"t",function(){return c}),n.d(e,"u",function(){return s}),n.d(e,"a",function(){return l}),n.d(e,"c",function(){return f}),n.d(e,"v",function(){return d}),n.d(e,"d",function(){return p}),n.d(e,"h",function(){return h}),n.d(e,"e",function(){return v}),n.d(e,"k",function(){return g}),n.d(e,"i",function(){return b}),n.d(e,"j",function(){return m}),n.d(e,"b",function(){return P}),n.d(e,"f",function(){return x}),n.d(e,"g",function(){return S}),n.d(e,"o",function(){return E}),n.d(e,"l",function(){return T}),n.d(e,"m",function(){return A}),n.d(e,"n",function(){return _}),n.d(e,"p",function(){return F}),n.d(e,"q",function(){return I}),n.d(e,"r",function(){return M}),n.d(e,"s",function(){return N}),n.d(e,"A",function(){return L}),n.d(e,"z",function(){return D}),n.d(e,"B",function(){return R});var r=n(0);function i(t,e){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:null;!function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}(this,t),this.code=Object(r.A)(n)?n:0,this.sourceError=i,e&&(this.key=e)}var e,n,o;return e=t,o=[{key:"logMessage",value:function(t){var e=t%1e3,n=Math.floor((t-e)/1e3),r=t;return e>=400&&e<600&&(r="".concat(n,"400-").concat(n,"599")),"JW Player ".concat(t>299999&&t<4e5?"Warning":"Error"," ").concat(t,". For more information see https://developer.jwplayer.com/jw-player/docs/developer-guide/api/errors-reference#").concat(r)}}],(n=null)&&i(e.prototype,n),o&&i(e,o),t}();function L(t,e,n){return n instanceof N&&n.code?n:new N(t,e,n)}function D(t,e){var n=L(M,e,t);return n.code=(t&&t.code||0)+e,n}function R(t){var e=t.name,n=t.message;switch(e){case"AbortError":return/pause/.test(n)?O:/load/.test(n)?w:j;case"NotAllowedError":return k;case"NotSupportedError":return C;default:return y}}},function(t,e,n){"use strict";n.d(e,"i",function(){return o}),n.d(e,"e",function(){return u}),n.d(e,"j",function(){return a}),n.d(e,"a",function(){return c}),n.d(e,"b",function(){return s}),n.d(e,"g",function(){return l}),n.d(e,"d",function(){return f}),n.d(e,"f",function(){return d}),n.d(e,"h",function(){return p}),n.d(e,"c",function(){return h});var r=n(0),i=window.parseFloat;function o(t){return t.replace(/^\s+|\s+$/g,"")}function u(t,e,n){for(t=""+t,n=n||"0";t.length-1?t.substr(t.lastIndexOf(".")+1,t.length).toLowerCase():void 0}function s(t){var e=(t/60|0)%60,n=t%60;return u(t/3600|0,2)+":"+u(e,2)+":"+u(n.toFixed(3),6)}function l(t,e){if(!t)return 0;if(Object(r.A)(t))return t;var n=t.replace(",","."),o=n.slice(-1),u=n.split(":"),a=u.length,c=0;if("s"===o)c=i(n);else if("m"===o)c=60*i(n);else if("h"===o)c=3600*i(n);else if(a>1){var s=a-1;4===a&&(e&&(c=i(u[s])/e),s-=1),c+=i(u[s]),c+=60*i(u[s-1]),a>=3&&(c+=3600*i(u[s-2]))}else c=i(n);return Object(r.A)(c)?c:0}function f(t,e,n){if(Object(r.y)(t)&&"%"===t.slice(-1)){var o=i(t);return e&&Object(r.A)(e)&&Object(r.A)(o)?e*o/100:null}return l(t,n)}function d(t,e){return t.map(function(t){return e+t})}function p(t,e){return t.map(function(t){return t+e})}function h(t){return"string"==typeof t&&"%"===t.slice(-1)}},function(t,e,n){"use strict";n.d(e,"kb",function(){return r}),n.d(e,"nb",function(){return i}),n.d(e,"lb",function(){return o}),n.d(e,"pb",function(){return u}),n.d(e,"qb",function(){return a}),n.d(e,"mb",function(){return c}),n.d(e,"ob",function(){return s}),n.d(e,"rb",function(){return l}),n.d(e,"s",function(){return f}),n.d(e,"u",function(){return d}),n.d(e,"t",function(){return p}),n.d(e,"n",function(){return h}),n.d(e,"q",function(){return v}),n.d(e,"sb",function(){return g}),n.d(e,"r",function(){return b}),n.d(e,"Z",function(){return m}),n.d(e,"W",function(){return y}),n.d(e,"v",function(){return j}),n.d(e,"Y",function(){return w}),n.d(e,"w",function(){return O}),n.d(e,"ub",function(){return k}),n.d(e,"a",function(){return C}),n.d(e,"b",function(){return P}),n.d(e,"c",function(){return x}),n.d(e,"d",function(){return S}),n.d(e,"e",function(){return E}),n.d(e,"h",function(){return T}),n.d(e,"F",function(){return A}),n.d(e,"hb",function(){return _}),n.d(e,"Q",function(){return F}),n.d(e,"C",function(){return I}),n.d(e,"B",function(){return M}),n.d(e,"E",function(){return N}),n.d(e,"p",function(){return L}),n.d(e,"cb",function(){return D}),n.d(e,"m",function(){return R}),n.d(e,"G",function(){return B}),n.d(e,"H",function(){return q}),n.d(e,"N",function(){return z}),n.d(e,"O",function(){return V}),n.d(e,"R",function(){return Q}),n.d(e,"jb",function(){return W}),n.d(e,"bb",function(){return X}),n.d(e,"D",function(){return U}),n.d(e,"S",function(){return H}),n.d(e,"P",function(){return Y}),n.d(e,"T",function(){return K}),n.d(e,"V",function(){return J}),n.d(e,"M",function(){return $}),n.d(e,"L",function(){return G}),n.d(e,"K",function(){return Z}),n.d(e,"I",function(){return tt}),n.d(e,"J",function(){return et}),n.d(e,"U",function(){return nt}),n.d(e,"o",function(){return rt}),n.d(e,"y",function(){return it}),n.d(e,"ib",function(){return ot}),n.d(e,"db",function(){return ut}),n.d(e,"eb",function(){return at}),n.d(e,"f",function(){return ct}),n.d(e,"g",function(){return st}),n.d(e,"ab",function(){return lt}),n.d(e,"A",function(){return ft}),n.d(e,"l",function(){return dt}),n.d(e,"k",function(){return pt}),n.d(e,"fb",function(){return ht}),n.d(e,"gb",function(){return vt}),n.d(e,"tb",function(){return gt}),n.d(e,"z",function(){return bt}),n.d(e,"j",function(){return mt}),n.d(e,"X",function(){return yt}),n.d(e,"i",function(){return jt}),n.d(e,"x",function(){return wt});var r="buffering",i="idle",o="complete",u="paused",a="playing",c="error",s="loading",l="stalled",f="drag",d="dragStart",p="dragEnd",h="click",v="doubleClick",g="tap",b="doubleTap",m="over",y="move",j="enter",w="out",O=c,k="warning",C="adClick",P="adPause",x="adPlay",S="adSkipped",E="adTime",T="autostartNotAllowed",A=o,_="ready",F="seek",I="beforePlay",M="beforeComplete",N="bufferFull",L="displayClick",D="playlistComplete",R="cast",B="mediaError",q="firstFrame",z="playAttempt",V="playAttemptFailed",Q="seeked",W="setupError",X="state",U="bufferChange",H="time",Y="ratechange",K="mediaType",J="volume",$="mute",G="metadataCueParsed",Z="meta",tt="levels",et="levelsChanged",nt="visualQuality",rt="controls",it="fullscreen",ot="resize",ut="playlistItem",at="playlist",ct="audioTracks",st="audioTrackChanged",lt="playbackRateChanged",ft="logoClick",dt="captionsList",pt="captionsChanged",ht="providerChanged",vt="providerFirstFrame",gt="userAction",bt="instreamClick",mt="breakpoint",yt="fullscreenchange",jt="bandwidthEstimate",wt="float"},function(t,e,n){"use strict";n.d(e,"b",function(){return i}),n.d(e,"d",function(){return o}),n.d(e,"a",function(){return u}),n.d(e,"c",function(){return a});var r=n(2);function i(t){var e="";return t&&(t.localName?e=t.localName:t.baseName&&(e=t.baseName)),e}function o(t){var e="";return t&&(t.textContent?e=Object(r.i)(t.textContent):t.text&&(e=Object(r.i)(t.text))),e}function u(t,e){return t.childNodes[e]}function a(t){return t.childNodes?t.childNodes.length:0}},function(t,e,n){"use strict";n.r(e);var r=n(6);function i(t,e){if(t&&t.length>e)return t[e]}var o=n(0);n.d(e,"Browser",function(){return a}),n.d(e,"OS",function(){return c}),n.d(e,"Features",function(){return s});var u=navigator.userAgent;var a={},c={},s={};Object.defineProperties(a,{androidNative:{get:Object(o.D)(r.c),enumerable:!0},chrome:{get:Object(o.D)(r.d),enumerable:!0},edge:{get:Object(o.D)(r.e),enumerable:!0},facebook:{get:Object(o.D)(r.g),enumerable:!0},firefox:{get:Object(o.D)(r.f),enumerable:!0},ie:{get:Object(o.D)(r.i),enumerable:!0},msie:{get:Object(o.D)(r.n),enumerable:!0},safari:{get:Object(o.D)(r.q),enumerable:!0},version:{get:Object(o.D)(function(t,e){var n,r,i,o;return t.chrome?n=-1!==e.indexOf("Chrome")?e.substring(e.indexOf("Chrome")+7):e.substring(e.indexOf("CriOS")+6):t.safari?n=e.substring(e.indexOf("Version")+8):t.firefox?n=e.substring(e.indexOf("Firefox")+8):t.edge?n=e.substring(e.indexOf("Edge")+5):t.ie&&(-1!==e.indexOf("rv:")?n=e.substring(e.indexOf("rv:")+3):-1!==e.indexOf("MSIE")&&(n=e.substring(e.indexOf("MSIE")+5))),n&&(-1!==(o=n.indexOf(";"))&&(n=n.substring(0,o)),-1!==(o=n.indexOf(" "))&&(n=n.substring(0,o)),-1!==(o=n.indexOf(")"))&&(n=n.substring(0,o)),r=parseInt(n,10),i=parseInt(n.split(".")[1],10)),{version:n,major:r,minor:i}}.bind(void 0,a,u)),enumerable:!0}}),Object.defineProperties(c,{android:{get:Object(o.D)(r.b),enumerable:!0},iOS:{get:Object(o.D)(r.j),enumerable:!0},mobile:{get:Object(o.D)(r.o),enumerable:!0},mac:{get:Object(o.D)(r.p),enumerable:!0},iPad:{get:Object(o.D)(r.k),enumerable:!0},iPhone:{get:Object(o.D)(r.l),enumerable:!0},windows:{get:Object(o.D)(function(){return u.indexOf("Windows")>-1}),enumerable:!0},version:{get:Object(o.D)(function(t,e){var n,r,o;if(t.windows)switch(n=i(/Windows(?: NT|)? ([._\d]+)/.exec(e),1)){case"6.1":n="7.0";break;case"6.2":n="8.0";break;case"6.3":n="8.1"}else t.android?n=i(/Android ([._\d]+)/.exec(e),1):t.iOS?n=i(/OS ([._\d]+)/.exec(e),1):t.mac&&(n=i(/Mac OS X (10[._\d]+)/.exec(e),1));if(n){r=parseInt(n,10);var u=n.split(/[._]/);u&&(o=parseInt(u[1],10))}return{version:n,major:r,minor:o}}.bind(void 0,c,u)),enumerable:!0}}),Object.defineProperties(s,{flash:{get:Object(o.D)(r.h),enumerable:!0},flashVersion:{get:Object(o.D)(r.a),enumerable:!0},iframe:{get:Object(o.D)(r.m),enumerable:!0},passiveEvents:{get:Object(o.D)(function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){return t=!0}});window.addEventListener("testPassive",null,e),window.removeEventListener("testPassive",null,e)}catch(t){}return t}),enumerable:!0},backgroundLoading:{get:Object(o.D)(function(){return!(c.iOS||a.safari)}),enumerable:!0}})},function(t,e,n){"use strict";n.d(e,"h",function(){return u}),n.d(e,"f",function(){return a}),n.d(e,"l",function(){return s}),n.d(e,"k",function(){return l}),n.d(e,"p",function(){return f}),n.d(e,"g",function(){return d}),n.d(e,"e",function(){return p}),n.d(e,"n",function(){return h}),n.d(e,"d",function(){return v}),n.d(e,"i",function(){return g}),n.d(e,"q",function(){return b}),n.d(e,"j",function(){return m}),n.d(e,"c",function(){return y}),n.d(e,"b",function(){return j}),n.d(e,"o",function(){return w}),n.d(e,"m",function(){return O}),n.d(e,"a",function(){return k});var r=navigator.userAgent;function i(t){return null!==r.match(t)}function o(t){return function(){return i(t)}}function u(){var t=k();return!!(t&&t>=18)}var a=o(/gecko\//i),c=o(/trident\/.+rv:\s*11/i),s=o(/iP(hone|od)/i),l=o(/iPad/i),f=o(/Macintosh/i),d=o(/FBAV/i);function p(){return i(/\sEdge\/\d+/i)}function h(){return i(/msie/i)}function v(){return i(/\s(?:(?:Headless)?Chrome|CriOS)\//i)&&!p()&&!i(/UCBrowser/i)}function g(){return p()||c()||h()}function b(){return i(/safari/i)&&!i(/(?:Chrome|CriOS|chromium|android|phantom)/i)}function m(){return i(/iP(hone|ad|od)/i)}function y(){return!(i(/chrome\/[123456789]/i)&&!i(/chrome\/18/i)&&!a())&&j()}function j(){return i(/Android/i)&&!i(/Windows Phone/i)}function w(){return m()||j()||i(/Windows Phone/i)}function O(){try{return window.self!==window.top}catch(t){return!0}}function k(){if(j())return 0;var t,e=navigator.plugins;if(e&&(t=e["Shockwave Flash"])&&t.description)return parseFloat(t.description.replace(/\D+(\d+\.?\d*).*/,"$1"));if(void 0!==window.ActiveXObject){try{if(t=new window.ActiveXObject("ShockwaveFlash.ShockwaveFlash"))return parseFloat(t.GetVariable("$version").split(" ")[1].replace(/\s*,\s*/,"."))}catch(t){return 0}return t}return 0}},function(t,e,n){"use strict";n.d(e,"h",function(){return a}),n.d(e,"e",function(){return c}),n.d(e,"p",function(){return s}),n.d(e,"i",function(){return l}),n.d(e,"r",function(){return f}),n.d(e,"q",function(){return d}),n.d(e,"t",function(){return p}),n.d(e,"d",function(){return g}),n.d(e,"a",function(){return b}),n.d(e,"n",function(){return m}),n.d(e,"o",function(){return y}),n.d(e,"u",function(){return j}),n.d(e,"s",function(){return w}),n.d(e,"g",function(){return O}),n.d(e,"b",function(){return k}),n.d(e,"f",function(){return C}),n.d(e,"c",function(){return P}),n.d(e,"l",function(){return x}),n.d(e,"j",function(){return S}),n.d(e,"m",function(){return E}),n.d(e,"k",function(){return T});var r,i=n(0),o=n(2),u=n(5);function a(t,e){return t.classList.contains(e)}function c(t){return l(t).firstChild}function s(t,e){O(t),function(t,e){if(!e)return;for(var n=document.createDocumentFragment(),r=l(e).childNodes,i=0;i0?"":"px")}function h(t){return Object(i.y)(t.className)?t.className.split(" "):[]}function v(t,e){e=Object(o.i)(e),t.className!==e&&(t.className=e)}function g(t){return t.classList?t.classList:h(t)}function b(t,e){var n=h(t);(Array.isArray(e)?e:e.split(" ")).forEach(function(t){Object(i.e)(n,t)||n.push(t)}),v(t,n.join(" "))}function m(t,e){var n=h(t),r=Array.isArray(e)?e:e.split(" ");v(t,Object(i.i)(n,r).join(" "))}function y(t,e,n){var r=t.className||"";e.test(r)?r=r.replace(e,n):n&&(r+=" "+n),v(t,r)}function j(t,e,n){var r=a(t,e);(n=Object(i.s)(n)?n:!r)!==r&&(n?b(t,e):m(t,e))}function w(t,e,n){t.setAttribute(e,n)}function O(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function k(t){var e=document.createElement("link");e.rel="stylesheet",e.href=t,document.getElementsByTagName("head")[0].appendChild(e)}function C(t){t&&O(t)}function P(t){var e={left:0,right:0,width:0,height:0,top:0,bottom:0};if(!t||!document.body.contains(t))return e;var n=t.getBoundingClientRect(),r=window.pageYOffset,i=window.pageXOffset;return n.width||n.height||n.left||n.top?(e.left=n.left+i,e.right=n.right+i,e.top=n.top+r,e.bottom=n.bottom+r,e.width=n.right-n.left,e.height=n.bottom-n.top,e):e}function x(t,e){t.insertBefore(e,t.firstChild)}function S(t){return t.nextElementSibling}function E(t){return t.previousElementSibling}function T(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=document.createElement("a");r.href=t,r.target=e,r=Object(i.k)(r,n),u.Browser.firefox?r.dispatchEvent(new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window})):r.click()}},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}n.r(e),n.d(e,"exists",function(){return o}),n.d(e,"isHTTPS",function(){return u}),n.d(e,"isFileProtocol",function(){return a}),n.d(e,"isRtmp",function(){return c}),n.d(e,"isYouTube",function(){return s}),n.d(e,"typeOf",function(){return l}),n.d(e,"isDeepKeyCompliant",function(){return f});var i=window.location.protocol;function o(t){switch(r(t)){case"string":return t.length>0;case"object":return null!==t;case"undefined":return!1;default:return!0}}function u(){return"https:"===i}function a(){return"file:"===i}function c(t,e){return 0===t.indexOf("rtmp:")||"rtmp"===e}function s(t,e){return"youtube"===e||/^(http|\/\/).*(youtube\.com|youtu\.be)\/.+/.test(t)}function l(t){if(null===t)return"null";var e=r(t);return"object"===e&&Array.isArray(t)?"array":e}function f(t,e,n){var i=Object.keys(t);return Object.keys(e).length>=i.length&&i.every(function(i){var o=t[i],u=e[i];return o&&"object"===r(o)?!(!u||"object"!==r(u))&&f(o,u,n):n(i,t)})}},function(t,e,n){"use strict";function r(t){return(r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function i(t,e){for(var n=0;n-1?t:parseInt(t.replace("px",""),10):t}function l(t,e){if(t<=0&&!e||Object(i.v)(parseInt(t)))return"00:00";var n=t<0?"-":"";t=Math.abs(t);var r=Math.floor(t/3600),o=Math.floor((t-3600*r)/60),u=Math.floor(t%60);return n+(r?r+":":"")+(o<10?"0":"")+o+":"+(u<10?"0":"")+u}},function(t,e,n){"use strict";n.d(e,"a",function(){return a});var r=n(33),i=n(17),o=n(56),u=n(0);function a(t){var e=t.getName().name;if(!r.a[e]){if(!Object(u.m)(i.a,Object(u.C)({name:e}))){if(!Object(u.u)(t.supports))throw new Error("Tried to register a provider with an invalid object");i.a.unshift({name:e,supports:t.supports})}Object(u.h)(t.prototype,o.a),r.a[e]=t}}},function(t,e,n){"use strict";n.d(e,"j",function(){return p}),n.d(e,"d",function(){return h}),n.d(e,"b",function(){return v}),n.d(e,"e",function(){return b}),n.d(e,"g",function(){return y}),n.d(e,"h",function(){return j}),n.d(e,"c",function(){return w}),n.d(e,"f",function(){return k}),n.d(e,"i",function(){return C}),n.d(e,"a",function(){return P});var r=n(0),i=n(6),o=n(28),u=n(8),a=n(40),c={},s={zh:"Chinese",nl:"Dutch",en:"English",fr:"French",de:"German",it:"Italian",ja:"Japanese",pt:"Portuguese",ru:"Russian",es:"Spanish",el:"Greek",fi:"Finnish",id:"Indonesian",ko:"Korean",th:"Thai",vi:"Vietnamese"},l=Object(r.r)(s);function f(t){var e=d(t),n=e.indexOf("_");return-1===n?e:e.substring(0,n)}function d(t){return t.toLowerCase().replace("-","_")}function p(t){return t?Object.keys(t).reduce(function(e,n){return e[d(n)]=t[n],e},{}):{}}function h(t){if(t)return 3===t.length?t:s[f(t)]||t}function v(t){return l[t]||""}function g(t){var e=t.querySelector("html");return e?e.getAttribute("lang"):null}function b(){var t=g(document);if(!t&&Object(i.m)())try{t=g(window.top.document)}catch(t){}return t||navigator.language||"en"}var m=["ar","da","de","es","fi","fr","he","id","it","ja","ko","nl","no","oc","pt","ro","ru","sl","sv","th","tr","vi","zh"];function y(t){return 8207===t.charCodeAt(0)||/^[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/.test(t)}function j(t){return m.indexOf(f(t))>=0}function w(t,e,n){return Object(r.k)({},function(t){var e=t.advertising,n=t.related,i=t.sharing,o=t.abouttext,u=Object(r.k)({},t.localization);e&&(u.advertising=u.advertising||{},O(u.advertising,e,"admessage"),O(u.advertising,e,"cuetext"),O(u.advertising,e,"loadingAd"),O(u.advertising,e,"podmessage"),O(u.advertising,e,"skipmessage"),O(u.advertising,e,"skiptext"));"string"==typeof u.related?u.related={heading:u.related}:u.related=u.related||{};n&&O(u.related,n,"autoplaymessage");i&&(u.sharing=u.sharing||{},O(u.sharing,i,"heading"),O(u.sharing,i,"copied"));o&&O(u,t,"abouttext");var a=u.close||u.nextUpClose;a&&(u.close=a);return u}(t),e[f(n)],e[d(n)])}function O(t,e,n){var r=t[n]||e[n];r&&(t[n]=r)}function k(t){return Object(u.isDeepKeyCompliant)(a.a,t,function(t,e){return"string"==typeof e[t]})}function C(t,e){var n=c[e];if(!n){var r="".concat(t,"translations/").concat(f(e),".json");c[e]=n=new Promise(function(t,n){Object(o.a)({url:r,oncomplete:t,onerror:function(t,r,i,o){c[e]=null,n(o)},responseType:"json"})})}return n}function P(t,e){var n=Object(r.k)({},t,e);return x(n,"errors",t,e),x(n,"related",t,e),x(n,"sharing",t,e),x(n,"advertising",t,e),n}function x(t,e,n,i){t[e]=Object(r.k)({},n[e],i[e])}},function(t,e,n){"use strict";e.a=[]},function(t,e,n){"use strict";e.a={debug:!1}},function(t,e,n){"use strict";var r=n(27),i=n(5),o=n(23),u=n(0),a=n(8),c=n(36),s=Object(u.m)(r.a,Object(u.C)({name:"html5"})),l=s.supports;function f(t){var e=window.MediaSource;return Object(u.a)(t,function(t){return!!e&&!!e.isTypeSupported&&e.isTypeSupported(t)})}function d(t){if(t.drm)return!1;var e=t.file.indexOf(".m3u8")>-1,n="hls"===t.type||"m3u8"===t.type;if(!e&&!n)return!1;var r=i.Browser.chrome||i.Browser.firefox||i.Browser.edge||i.Browser.ie&&11===i.Browser.version.major,o=i.OS.android&&!1===t.hlsjsdefault,u=i.Browser.safari&&!!t.safarihlsjs;return f(t.mediaTypes||['video/mp4;codecs="avc1.4d400d,mp4a.40.2"'])&&(r||u)&&!o}s.supports=function(t,e){var n=l.apply(this,arguments);if(n&&t.drm&&"hls"===t.type){var r=Object(o.a)(e)("drm");if(r&&t.drm.fairplay){var i=window.WebKitMediaKeys;return i&&i.isTypeSupported&&i.isTypeSupported("com.apple.fps.1_0","video/mp4")}return r}return n},r.a.push({name:"shaka",supports:function(t){return!(t.drm&&!Object(c.a)(t.drm))&&(!(!window.HTMLVideoElement||!window.MediaSource)&&(f(t.mediaTypes)&&("dash"===t.type||"mpd"===t.type||(t.file||"").indexOf("mpd-time-csf")>-1)))}}),r.a.splice(0,0,{name:"hlsjs",supports:function(t){return!t._hlsjsProgressive&&d(t)}}),r.a.splice(1,0,{name:"hlsjsProgressive",supports:d}),r.a.push({name:"flash",supports:function(t){if(!i.Features.flash||t.drm)return!1;var e=t.type;return"hls"===e||"m3u8"===e||!Object(a.isRtmp)(t.file,e)&&["flv","f4v","mov","m4a","m4v","mp4","aac","f4a","mp3","mpeg","smil"].indexOf(e)>-1}}),e.a=r.a},function(t,e,n){"use strict";n.d(e,"a",function(){return r});var r=Date.now||function(){return(new Date).getTime()}},function(t,e,n){"use strict";n.d(e,"b",function(){return i}),n.d(e,"c",function(){return o}),n.d(e,"a",function(){return u});var r=n(0),i=function(t){return t.replace(/^(.*\/)?([^-]*)-?.*\.(js)$/,"$2")};function o(t){var e=305e3;if(!t)return e;switch(i(t)){case"jwpsrv":e=305001;break;case"googima":e=305002;break;case"vast":e=305003;break;case"freewheel":e=305004;break;case"dai":e=305005;break;case"gapro":e=305006}return e}function u(t,e,n){var i=t.name,o=document.createElement("div");o.id=n.id+"_"+i,o.className="jw-plugin jw-reset";var u=Object(r.k)({},e),a=t.getNewInstance(n,u,o);return n.addPlugin(i,a),a}},function(t,e,n){"use strict";n.r(e),n.d(e,"getScriptPath",function(){return o}),n.d(e,"repo",function(){return u}),n.d(e,"versionCheck",function(){return a}),n.d(e,"loadFrom",function(){return c});var r=n(31),i=n(8),o=function(t){for(var e=document.getElementsByTagName("script"),n=0;n=0)return r.substr(0,i+1)}}return""},u=function(){var t="//ssl.p.jwpcdn.com/player/v/8.9.3/",e=Object(i.isFileProtocol)()?"https:":"";return"".concat(e).concat(t)},a=function(t){var e=("0"+t).split(/\W/),n=r.a.split(/\W/),i=parseFloat(e[0]),o=parseFloat(n[0]);return!(i>o)&&!(i===o&&parseFloat("0"+e[1])>parseFloat(n[1]))},c=function(){return u()}},,,function(t,e,n){"use strict";n.d(e,"a",function(){return h});var r="free",i="starter",o="business",u="premium",a="enterprise",c="developer",s="platinum",l="ads",f="unlimited",d="trial",p="invalid";function h(t){var e={setup:[r,i,o,u,a,c,l,f,d,s],drm:[a,c,l,f,d],ads:[l,f,d,s,a,c,o],jwpsrv:[r,i,o,u,a,c,l,d,s,p],discovery:[l,a,c,d,f]};return function(n){return e[n]&&e[n].indexOf(t)>-1}}},function(t,e,n){"use strict";var r=n(0),i=n(9),o=n(3),u={},a=45e3,c=2,s=3;function l(t){var e=document.createElement("link");return e.type="text/css",e.rel="stylesheet",e.href=t,e}function f(t,e){var n=document.createElement("script");return n.type="text/javascript",n.charset="utf-8",n.async=!0,n.timeout=e||a,n.src=t,n}var d=function(t,e,n){var r=this,i=0;function d(t){i=c,r.trigger(o.w,t).off()}function p(t){i=s,r.trigger(o.lb,t).off()}this.getStatus=function(){return i},this.load=function(){var r=u[t];return 0!==i?r:(r&&r.then(p).catch(d),i=1,r=new Promise(function(r,i){var o=(e?l:f)(t,n),u=function(){o.onerror=o.onload=null,clearTimeout(s)},c=function(t){u(),d(t),i(t)},s=setTimeout(function(){c(new Error("Network timeout ".concat(t)))},a);o.onerror=function(){c(new Error("Failed to load ".concat(t)))},o.onload=function(t){u(),p(t),r(t)};var h=document.getElementsByTagName("head")[0]||document.documentElement;h.insertBefore(o,h.firstChild)}),u[t]=r,r)}};Object(r.k)(d.prototype,i.a),e.a=d},function(t,e,n){"use strict";var r=n(1),i=n(19);function o(t){return(o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var u=function(){this.load=function(t,e,n,u){return n&&"object"===o(n)?Promise.all(Object.keys(n).filter(function(t){return t}).map(function(o){var a=n[o];return e.setupPlugin(o).then(function(e){if(!u.attributes._destroyed)return Object(i.a)(e,a,t)}).catch(function(t){return e.removePlugin(o),t.code?t:new r.s(null,Object(i.c)(o),t)})})):Promise.resolve()}},a=n(57),c=n(46),s={},l=function(){},f=l.prototype;f.setupPlugin=function(t){var e=this.getPlugin(t);return e?(e.url!==t&&Object(c.a)('JW Plugin "'.concat(Object(i.b)(t),'" already loaded from "').concat(e.url,'". Ignoring "').concat(t,'."')),e.promise):this.addPlugin(t).load()},f.addPlugin=function(t){var e=Object(i.b)(t),n=s[e];return n||(n=new a.a(t),s[e]=n),n},f.getPlugin=function(t){return s[Object(i.b)(t)]},f.removePlugin=function(t){delete s[Object(i.b)(t)]},f.getPlugins=function(){return s};var d=l;n.d(e,"b",function(){return h}),n.d(e,"a",function(){return v});var p=new d,h=function(t,e,n){var r=p.addPlugin(t);r.js||r.registerPlugin(t,e,n)};function v(t,e){var n=t.get("plugins");return window.jwplayerPluginJsonp=h,(t.pluginLoader=t.pluginLoader||new u).load(e,p,n,t).then(function(e){if(!t.attributes._destroyed)return delete window.jwplayerPluginJsonp,e})}},function(t,e,n){"use strict";n.d(e,"a",function(){return a});var r=n(47),i=n(23),o=n(44),u=n(1),a=100013;e.b=function(t){var e,n,c;try{var s=Object(r.a)(t||"",Object(o.a)("NDh2aU1Cb0NHRG5hcDFRZQ==")).split("/");if("pro"===(e=s[0])&&(e="premium"),Object(i.a)(e)("setup")||(e="invalid"),s.length>2){n=s[1];var l=parseInt(s[2]);l>0&&(c=new Date).setTime(l)}}catch(t){e="invalid"}this.edition=function(){return e},this.token=function(){return n},this.expiration=function(){return c},this.duration=function(){return c?c.getTime()-(new Date).getTime():0},this.error=function(){var r;return void 0===t?r=100011:"invalid"!==e&&n?this.duration()<0&&(r=a):r=100012,r?new u.s(u.m,r):null}}},function(t,e,n){"use strict";n.d(e,"b",function(){return c});var r=n(63),i=n(8),o=n(39),u={aac:"audio/mp4",mp4:"video/mp4",f4v:"video/mp4",m4v:"video/mp4",mov:"video/mp4",mp3:"audio/mpeg",mpeg:"audio/mpeg",ogv:"video/ogg",ogg:"video/ogg",oga:"video/ogg",vorbis:"video/ogg",webm:"video/webm",f4a:"video/aac",m3u8:"application/vnd.apple.mpegurl",m3u:"application/vnd.apple.mpegurl",hls:"application/vnd.apple.mpegurl"},a=[{name:"html5",supports:c}];function c(t){if(!1===Object(r.a)(t))return!1;if(!o.a.canPlayType)return!1;var e=t.file,n=t.type;if(Object(i.isRtmp)(e,n))return!1;var a=t.mimeType||u[n];if(!a)return!1;var c=t.mediaTypes;return c&&c.length&&(a=[a].concat(c.slice()).join("; ")),!!o.a.canPlayType(a)}e.a=a},function(t,e,n){"use strict";n.d(e,"a",function(){return m});var r=n(0),i=n(12),o=n(8),u=n(1),a=1,c=2,s=3,l=4,f=5,d=6,p=7,h=601,v=602,g=611,b=function(){};function m(t,e,n,h){var O;t===Object(t)&&(t=(h=t).url);var k=Object(r.k)({xhr:null,url:t,withCredentials:!1,retryWithoutCredentials:!1,timeout:6e4,timeoutId:-1,oncomplete:e||b,onerror:n||b,mimeType:h&&!h.responseType?"text/xml":"",requireValidXML:!1,responseType:h&&h.plainText?"text":"",useDomParser:!1,requestFilter:null},h),C=function(t,e){return function(t,n){var i=t.currentTarget||e.xhr;if(clearTimeout(e.timeoutId),e.retryWithoutCredentials&&e.xhr.withCredentials){y(i);var o=Object(r.k)({},e,{xhr:null,withCredentials:!1,retryWithoutCredentials:!1});m(o)}else!n&&i.status>=400&&i.status<600&&(n=i.status),j(e,n?u.o:u.r,n||d,t)}}(0,k);if("XMLHttpRequest"in window){if(O=k.xhr=k.xhr||new window.XMLHttpRequest,"function"==typeof k.requestFilter){var P;try{P=k.requestFilter({url:t,xhr:O})}catch(t){return C(t,f),O}P&&"open"in P&&"send"in P&&(O=k.xhr=P)}O.onreadystatechange=function(t){return function(e){var n=e.currentTarget||t.xhr;if(4===n.readyState){clearTimeout(t.timeoutId);var a=n.status;if(a>=400)return void j(t,u.o,a<600?a:d);if(200===a)return function(t){return function(e){var n=e.currentTarget||t.xhr;if(clearTimeout(t.timeoutId),t.responseType){if("json"===t.responseType)return function(t,e){if(!t.response||"string"==typeof t.response&&'"'!==t.responseText.substr(1))try{t=Object(r.k)({},t,{response:JSON.parse(t.responseText)})}catch(t){return void j(e,u.o,g,t)}return e.oncomplete(t)}(n,t)}else{var o,a=n.responseXML;if(a)try{o=a.firstChild}catch(t){}if(a&&o)return w(n,a,t);if(t.useDomParser&&n.responseText&&!a&&(a=Object(i.parseXML)(n.responseText))&&a.firstChild)return w(n,a,t);if(t.requireValidXML)return void j(t,u.o,v)}t.oncomplete(n)}}(t)(e);0===a&&Object(o.isFileProtocol)()&&!/^[a-z][a-z0-9+.-]*:/.test(t.url)&&j(t,u.o,p)}}}(k),O.onerror=C,"overrideMimeType"in O?k.mimeType&&O.overrideMimeType(k.mimeType):k.useDomParser=!0;try{t=t.replace(/#.*$/,""),O.open("GET",t,!0)}catch(t){return C(t,s),O}if(k.responseType)try{O.responseType=k.responseType}catch(t){}k.timeout&&(k.timeoutId=setTimeout(function(){y(O),j(k,u.r,a)},k.timeout),O.onabort=function(){clearTimeout(k.timeoutId)});try{k.withCredentials&&"withCredentials"in O&&(O.withCredentials=!0),O.send()}catch(t){C(t,l)}return O}j(k,u.r,c)}function y(t){t.onload=null,t.onprogress=null,t.onreadystatechange=null,t.onerror=null,"abort"in t&&t.abort()}function j(t,e,n,r){t.onerror(e,t.url,t.xhr,new u.s(e,n,r))}function w(t,e,n){var i=e.documentElement;if(!n.requireValidXML||"parsererror"!==i.nodeName&&!i.getElementsByTagName("parsererror").length)return t.responseXML||(t=Object(r.k)({},t,{responseXML:e})),n.oncomplete(t);j(n,u.o,h)}},function(t,e,n){"use strict";var r=n(0),i=n(34),o=function(t){if(t&&t.file)return Object(r.k)({},{kind:"captions",default:!1},t)},u=Array.isArray;e.a=function(t){u((t=t||{}).tracks)||delete t.tracks;var e=Object(r.k)({},{sources:[],tracks:[],minDvrWindow:120,dvrSeekLimit:25},t);e.dvrSeekLimit<5&&(e.dvrSeekLimit=5),e.sources!==Object(e.sources)||u(e.sources)||(e.sources=[Object(i.a)(e.sources)]),u(e.sources)&&0!==e.sources.length||(t.levels?e.sources=t.levels:e.sources=[Object(i.a)(t)]);for(var n=0;nk*k&&(L(t,i.u,e),t.dragged=!0,L(t,i.s,e))}n||"touchmove"!==e.type||R(e)},s=function(n){if(clearTimeout(h),t.el)if(M(t),I(t,y),t.dragged)t.dragged=!1,L(t,i.t,n);else if(-1===n.type.indexOf("cancel")&&e.contains(n.target)){if(Object(u.a)()-t.lastStart>P)return;var r="pointerup"===n.type||"pointercancel"===n.type,o="mouseup"===n.type||r&&"mouse"===n.pointerType;!function(t,e,n){if(t.enableDoubleTap)if(Object(u.a)()-t.lastClick4&&void 0!==arguments[4]?arguments[4]:O,o=t.handlers[e],u=t.options[e];if(o||(o=t.handlers[e]={},u=t.options[e]={}),o[n])throw new Error("".concat(e," ").concat(n," already registered"));o[n]=r,u[n]=i;var a=t.el;(e===y?_(a):a).addEventListener(n,r,i)}function I(t,e){var n=t.el,r=t.handlers,i=t.options,o=e===y?_(n):n,u=r[e],a=i[e];u&&(Object.keys(u).forEach(function(t){var e=a[t];"boolean"==typeof e?o.removeEventListener(t,u[t],e):o.removeEventListener(t,u[t])}),r[e]=null,i[e]=null)}function M(t){var e=t.el;null!==t.pointerId&&(e.releasePointerCapture(t.pointerId),t.pointerId=null)}function N(t,e,n){var r=t.el,i=n.target;t.trigger(e,{type:e,sourceEvent:n,currentTarget:r,target:i})}function L(t,e,n){var r=function(t,e,n){var r,i=e.target,o=e.touches,u=e.changedTouches,a=e.pointerType;o||u?(r=o&&o.length?o[0]:u[0],a=a||"touch"):(r=e,a=a||"mouse");var c=r,s=c.pageX,l=c.pageY;return{type:t,pointerType:a,pageX:s,pageY:l,sourceEvent:e,currentTarget:n,target:i}}(e,n,t.el);t.trigger(e,r)}function D(t){return 0===t.type.indexOf("touch")?(t.originalEvent||t).changedTouches[0]:t}function R(t){t.preventDefault&&t.preventDefault()}},function(t,e,n){"use strict";n.d(e,"b",function(){return c}),n.d(e,"d",function(){return s}),n.d(e,"c",function(){return l}),n.d(e,"a",function(){return f});var r,i=n(23),o=[{configName:"clearkey",keyName:"org.w3.clearkey"},{configName:"widevine",keyName:"com.widevine.alpha"},{configName:"playready",keyName:"com.microsoft.playready"}],u=[],a={};function c(t){return t.some(function(t){return!!t.drm||t.sources.some(function(t){return!!t.drm})})}function s(t){return r||((navigator.requestMediaKeySystemAccess&&MediaKeySystemAccess.prototype.getConfiguration||window.MSMediaKeys)&&Object(i.a)(t)("drm")?(o.forEach(function(t){var e,n,r=(e=t.keyName,n=[{initDataTypes:["cenc"],videoCapabilities:[{contentType:'video/mp4;codecs="avc1.4d401e"'}],audioCapabilities:[{contentType:'audio/mp4;codecs="mp4a.40.2"'}]}],navigator.requestMediaKeySystemAccess?navigator.requestMediaKeySystemAccess(e,n):new Promise(function(t,n){var r;try{r=new window.MSMediaKeys(e)}catch(t){return void n(t)}t(r)})).then(function(){a[t.configName]=!0}).catch(function(){a[t.configName]=!1});u.push(r)}),r=Promise.all(u)):Promise.resolve())}function l(t){return a[t]}function f(t){if(r)return Object.keys(t).some(function(t){return l(t)})}},,function(t,e,n){"use strict";n.d(e,"a",function(){return o}),n.d(e,"b",function(){return u});var r=n(10),i=null,o={};function u(){return i||(i=n.e(1).then(function(t){var e=n(21).default;return o.controls=e,e}.bind(null,n)).catch(function(){i=null,Object(r.c)(301130)()})),i}},function(t,e,n){"use strict";var r=document.createElement("video");e.a=r},function(t,e,n){"use strict";e.a={advertising:{admessage:"This ad will end in xx",cuetext:"Advertisement",displayHeading:"Advertisement",loadingAd:"Loading ad",podmessage:"Ad __AD_POD_CURRENT__ of __AD_POD_LENGTH__.",skipmessage:"Skip ad in xx",skiptext:"Skip"},airplay:"AirPlay",audioTracks:"Audio Tracks",auto:"Auto",buffer:"Loading",cast:"Chromecast",cc:"Closed Captions",close:"Close",errors:{badConnection:"This video cannot be played because of a problem with your internet connection.",cantLoadPlayer:"Sorry, the video player failed to load.",cantPlayInBrowser:"The video cannot be played in this browser.",cantPlayVideo:"This video file cannot be played.",errorCode:"Error Code",liveStreamDown:"The live stream is either down or has ended.",protectedContent:"There was a problem providing access to protected content.",technicalError:"This video cannot be played because of a technical error."},exitFullscreen:"Exit Fullscreen",fullscreen:"Fullscreen",hd:"Quality",liveBroadcast:"Live",logo:"Logo",mute:"Mute",next:"Next",nextUp:"Next Up",notLive:"Not Live",off:"Off",pause:"Pause",play:"Play",playback:"Play",playbackRates:"Playback Rates",player:"Video Player",poweredBy:"Powered by",prev:"Previous",related:{autoplaymessage:"Next up in xx",heading:"More Videos"},replay:"Replay",rewind:"Rewind 10 Seconds",settings:"Settings",sharing:{copied:"Copied",email:"Email",embed:"Embed",heading:"Share",link:"Link"},slider:"Seek",stop:"Stop",unmute:"Unmute",videoInfo:"About This Video",volume:"Volume",volumeSlider:"Volume"}},function(t,e){var n,r,i={},o={},u=(n=function(){return document.head||document.getElementsByTagName("head")[0]},function(){return void 0===r&&(r=n.apply(this,arguments)),r});function a(t){var e=document.createElement("style");return e.type="text/css",e.setAttribute("data-jwplayer-id",t),function(t){u().appendChild(t)}(e),e}function c(t,e){var n,r,i,u=o[t];u||(u=o[t]={element:a(t),counter:0});var c=u.counter++;return n=u.element,i=function(){f(n,c,"")},(r=function(t){f(n,c,t)})(e.css),function(t){if(t){if(t.css===e.css&&t.media===e.media)return;r((e=t).css)}else i()}}t.exports={style:function(t,e){!function(t,e){for(var n=0;n')+'
'+'
'.concat(e||"",'').concat(i,"
")+"
"},i=n(7),o=n(11);function u(t,e){var n=e.message,u=e.code,a=r(t.get("id"),n,t.get("localization").errors.errorCode,u),c=t.get("width"),s=t.get("height"),l=Object(i.e)(a);return Object(o.d)(l,{width:c.toString().indexOf("%")>0?c:"".concat(c,"px"),height:s.toString().indexOf("%")>0?s:"".concat(s,"px")}),l}n.d(e,"a",function(){return u})},function(t,e,n){"use strict";n.d(e,"a",function(){return r});var r=window.atob},function(t,e,n){"use strict";var r=n(4),i=n(2);function o(t){for(var e=[],n=0;n0&&(n=t(l,n));break;case"title":n.title=Object(r.d)(l);break;case"description":n.description=Object(r.d)(l);break;case"guid":n.mediaid=Object(r.d)(l);break;case"thumbnail":n.image||(n.image=Object(i.j)(l,"url"));break;case"group":t(l,n);break;case"subtitle":var p={};p.file=Object(i.j)(l,"url"),p.kind="captions",Object(i.j)(l,"lang").length>0&&(p.label=(u=Object(i.j)(l,"lang"),a=void 0,(a={zh:"Chinese",nl:"Dutch",en:"English",fr:"French",de:"German",it:"Italian",ja:"Japanese",pt:"Portuguese",ru:"Russian",es:"Spanish"})[u]?a[u]:u)),c.push(p)}}}n.hasOwnProperty("tracks")||(n.tracks=[]);for(var h=0;h0&&(o[f][n]="true"===o[f][n],o[f].label.length||delete o[f].label,e.sources.push(o[f]))}if(u.length){e.tracks=[];for(var d=0;d0&&(u[d][n]="true"===u[d][n],u[d].kind=u[d].kind.length?u[d].kind:"captions",u[d].label.length||delete u[d].label,e.tracks.push(u[d]))}return e},s=n(29);function l(t){var e=[];e.feedData={};for(var n=0;n>>2&3;for(var p=s-1;p>=0;p--)o=((l=a[p>0?p-1:s-1])>>>5^f<<2)+(f>>>3^l<<4)^(d^f)+(c[3&p^u]^l),f=a[p]-=o;d-=2654435769}return function(t){try{return decodeURIComponent(escape(t))}catch(e){return t}}(function(t){for(var e=new Array(t.length),n=0;n>>8&255,t[n]>>>16&255,t[n]>>>24&255);return e.join("")}(a).replace(/\0+$/,""))}},function(t,e,n){"use strict";n.d(e,"b",function(){return r}),n.d(e,"a",function(){return i});var r={audioMode:!1,flashBlocked:!1,item:0,itemMeta:{},playbackRate:1,playRejected:!1,state:n(3).nb,itemReady:!1,controlsEnabled:!1},i={position:0,duration:0,buffer:0,currentTime:0}},function(t,e,n){"use strict";n.d(e,"b",function(){return r}),n.d(e,"a",function(){return i});var r=window.requestAnimationFrame||function(t){return setTimeout(t,17)},i=window.cancelAnimationFrame||clearTimeout},,function(t,e,n){"use strict";n.d(e,"a",function(){return r});var r=function(t,e,n){return Math.max(Math.min(t,n),e)}},function(t,e,n){"use strict";n.d(e,"a",function(){return r}),n.d(e,"b",function(){return o});var r=12;function i(){try{var t=window.crypto||window.msCrypto;if(t&&t.getRandomValues)return t.getRandomValues(new Uint32Array(1))[0].toString(36)}catch(t){}return Math.random().toString(36).slice(2,9)}function o(t){for(var e="";e.length0;){var e=r.shift(),n=e.command,o=e.args;(i[n]||t[n]).apply(t,o)}}e.forEach(function(e){var u=t[e];i[e]=u,t[e]=function(){var t=Array.prototype.slice.call(arguments,0);n()?r.push({command:e,args:t}):(o(),u&&u.apply(this,t))}}),Object.defineProperty(this,"queue",{enumerable:!0,get:function(){return r}}),this.flush=o,this.empty=function(){r.length=0},this.off=function(){e.forEach(function(e){var n=i[e];n&&(t[e]=n,delete i[e])})},this.destroy=function(){this.off(),this.empty()}}n.d(e,"a",function(){return r})},function(t,e,n){"use strict";n.d(e,"c",function(){return r}),n.d(e,"b",function(){return i}),n.d(e,"a",function(){return o});var r=4,i=2,o=1},function(t,e,n){"use strict";var r=n(3),i=function(){},o=function(){return!1},u={name:"default"},a={supports:o,play:i,pause:i,preload:i,load:i,stop:i,volume:i,mute:i,seek:i,resize:i,remove:i,destroy:i,eventsOn_:i,eventsOff_:i,setVisibility:i,setFullscreen:i,getFullscreen:o,supportsFullscreen:o,getContainer:i,setContainer:i,getName:function(){return u},getQualityLevels:i,getCurrentQuality:i,setCurrentQuality:i,getAudioTracks:i,getCurrentAudioTrack:i,setCurrentAudioTrack:i,getSeekRange:function(){return{start:0,end:this.getDuration()}},setPlaybackRate:i,getPlaybackRate:function(){return 1},getBandwidthEstimate:function(){return null},getLiveLatency:function(){return null},setControls:i,attachMedia:i,detachMedia:i,init:i,setState:function(t){this.state=t,this.trigger(r.bb,{newstate:t})},sendMediaType:function(t){var e=t[0],n=e.type,i=e.mimeType,o="aac"===n||"mp3"===n||"mpeg"===n||i&&0===i.indexOf("audio/");this.trigger(r.T,{mediaType:o?"audio":"video"})}};e.a=a},function(t,e,n){"use strict";var r=n(0),i=n(24),o=n(12),u=n(2),a=n(1),c=n(19),s=0,l=1,f=function(t){if("string"==typeof t){var e=(t=t.split("?")[0]).indexOf("://");if(e>0)return s;var n=t.indexOf("/"),r=Object(u.a)(t);return!(e<0&&n<0)||r&&isNaN(r)?l:2}};var d=function(t){this.url=t,this.promise_=null};Object.defineProperties(d.prototype,{promise:{get:function(){return this.promise_||this.load()},set:function(){}}}),Object(r.k)(d.prototype,{load:function(){var t=this,e=this.promise_;if(!e){if(2===f(this.url))e=Promise.resolve(this);else{var n=new i.a(function(t){switch(f(t)){case s:return t;case l:return Object(o.getAbsolutePath)(t,window.location.href)}}(this.url));this.loader=n,e=n.load().then(function(){return t})}this.promise_=e}return e},registerPlugin:function(t,e,n){this.name=t,this.target=e,this.js=n},getNewInstance:function(t,e,n){var r=this.js;if("function"!=typeof r)throw new a.s(null,Object(c.c)(this.url)+100);var i=new r(t,e,n);return i.addToPlayer=function(){var e=t.getContainer().querySelector(".jw-overlays");e&&(n.left=e.style.left,n.top=e.style.top,e.appendChild(n),i.displayArea=e)},i.resizeHandler=function(){var t=i.displayArea;t&&i.resize(t.clientWidth,t.clientHeight)},i}}),e.a=d},function(t,e,n){"use strict";var r=n(0),i=n(3),o=n(4),u=n(45),a=n(28),c=n(9),s=n(1);e.a=function(){var t=Object(r.k)(this,c.a);function e(e){try{var a,c=e.responseXML?e.responseXML.childNodes:null,l="";if(c){for(var f=0;f=.25&&t<=4}).map(function(t){return Math.round(100*t)/100})).indexOf(1)<0&&b.push(1),b.sort(),h.playbackRateControls=!0,h.playbackRates=b}(!h.playbackRateControls||h.playbackRates.indexOf(h.defaultPlaybackRate)<0)&&(h.defaultPlaybackRate=1),h.playbackRate=h.defaultPlaybackRate,h.aspectratio||delete h.aspectratio;var m=h.playlist;if(m)Array.isArray(m.playlist)&&(h.feedData=m,h.playlist=m.playlist);else{var y=Object(r.E)(h,["title","description","type","mediaid","image","file","sources","tracks","preload","duration"]);h.playlist=[y]}h.qualityLabels=h.qualityLabels||h.hlslabels,delete h.duration;var j=h.liveTimeout;null!==j&&(Object(r.A)(j)?0!==j&&(j=Math.max(30,j)):j=null,h.liveTimeout=j);var w,O,k=parseFloat(h.bandwidthEstimate),C=parseFloat(h.bitrateSelection);return h.bandwidthEstimate=Object(r.A)(k)?k:(w=h.defaultBandwidthEstimate,O=parseFloat(w),Object(r.A)(O)?Math.max(O,1):l.bandwidthEstimate),h.bitrateSelection=Object(r.A)(C)?C:l.bitrateSelection,h.backgroundLoading=Object(r.s)(h.backgroundLoading)?h.backgroundLoading:a.Features.backgroundLoading,h},p=n(26),h=n(8),v=n(23),g="__CONTEXTUAL__";function b(t,e){var n=t.querySelector(e);if(n)return n.getAttribute("content")}function m(t){return"string"==typeof t&&/^\/\/(?:content\.jwplatform|cdn\.jwplayer)\.com\//.test(t)}function y(t){return"https:"+t}function j(t){var e="file:"===window.location.protocol?"https:":"",n={jwpsrv:"//ssl.p.jwpcdn.com/player/v/8.9.3/jwpsrv.js",dai:"//ssl.p.jwpcdn.com/player/plugins/dai/v/0.4.9/dai.js",vast:"//ssl.p.jwpcdn.com/player/plugins/vast/v/8.6.1/vast.js",googima:"//ssl.p.jwpcdn.com/player/plugins/googima/v/8.6.2/googima.js",freewheel:"//ssl.p.jwpcdn.com/player/plugins/freewheel/v/2.2.4/freewheel.js",gapro:"//ssl.p.jwpcdn.com/player/plugins/gapro/v/2.1.5/gapro.js"}[t];return n?e+n:""}function w(t,e,n){e&&(t[e.client||j(n)]=e,delete e.client)}var O=function(t,e){var i,u=d(t,e),a=u.key||window.jwplayer&&window.jwplayer.key,c=new p.b(a),s=c.edition();if(u.key=a,u.edition=s,u.error=c.error(),"unlimited"===s){var l=Object(o.getScriptPath)("jwplayer.js");if(!l)throw new Error("Error setting up player: Could not locate jwplayer.js script tag");n.p=l}if(u.flashplayer=function(t){var e=t.flashplayer;return e||(e=(Object(o.getScriptPath)("jwplayer.js")||t.base)+"jwplayer.flash.swf"),"http:"===window.location.protocol&&(e=e.replace(/^https/,"http")),e}(u),u.plugins=function(t){var e=Object(r.k)({},t.plugins),n=t.edition,i=Object(v.a)(n);if(i("ads")){var o=Object(r.k)({},t.advertising),u=o.client;if(u){var a=j(u)||u;e[a]=o,delete o.client}}if(i("jwpsrv")){var c=t.analytics;c!==Object(c)&&(c={}),w(e,c,"jwpsrv")}w(e,t.ga,"gapro");var s=t.related,l=!i("discovery")||s!==Object(s),f=!s||"none"!==s.displayMode,d=s||{},p=void 0===d.oncomplete?"none":d.oncomplete,h=d.autoplaytimer;!1===p||t.repeat?p="hide":"none"===p&&(h=0);var g="autoplay"===p&&h<=0||"none"===p;return t.related=Object(r.k)({},s,{disableRelated:l,showButton:f,oncomplete:p,autoplaytimer:h,shouldAutoAdvance:g}),e}(u),u.ab&&(u.ab=function(t){var e=t.ab;return e.clone&&(e=e.clone()),Object.keys(e.tests).forEach(function(n){e.tests[n].forEach(function(e){e.addConfig&&e.addConfig(t,e.selection)})}),e}(u)),i=u.playlist,Object(r.y)(i)&&i.indexOf(g)>-1&&(u.playlist=function(t,e){var n=(t.querySelector("title")||{}).textContent,r=b(t,'meta[property="og:title"]'),i=encodeURIComponent(r||n||""),o=b(t,'meta[property="og:description"]')||b(t,'meta[name="description"]');return o&&(i+="&page_description="+encodeURIComponent(o)),e.replace(g,i)}(document,u.playlist),u.contextual=!0),Object(h.isFileProtocol)()){var f=u.playlist,O=u.related;m(f)&&(u.playlist=y(f)),O&&m(O.file)&&(O.file=y(O.file))}return u},k=n(10),C=n(25),P=n(3),x=n(58),S=n(30),E=n(24),T=n(1);function A(t){var e=t.get("playlist");return new Promise(function(n,r){if("string"!=typeof e){var i=t.get("feedData")||{};return _(t,e,i),n()}var o=new x.a;o.on(P.eb,function(e){var r=e.playlist;delete e.playlist,_(t,r,e),n()}),o.on(P.w,function(e){_(t,[],{}),r(Object(T.z)(e,T.u))}),o.load(e)})}function _(t,e,n){var r=t.attributes;r.playlist=Object(S.a)(e),r.feedData=n}function F(t){return t.attributes._destroyed}var I=n(36);function M(t){return D(t)?Promise.resolve():A(t).then(function(){if(t.get("drm")||Object(I.b)(t.get("playlist")))return Object(I.d)(t.get("edition"))}).then(function(){return A(e=t).then(function(){if(!F(e)){var t=Object(S.b)(e.get("playlist"),e);e.attributes.playlist=t;try{Object(S.e)(t)}catch(t){throw t.code+=T.u,t}var n=e.getProviders(),r=n.choose(t[0].sources[0]),i=r.provider,o=r.name;return"function"==typeof i?i:k.a.html5&&"html5"===o?k.a.html5:n.load(o).catch(function(t){throw Object(T.z)(t,T.v)})}});var e})}function N(t,e){var n=[L(t)];return D(t)||n.push(Promise.resolve()),Promise.all(n)}function L(t){var e=t.attributes,n=e.error;if(n&&n.code===p.a){var r=e.pid,i=e.ph,o=new p.b(e.key);if(i>0&&i<4&&r&&o.duration()>-7776e6)return new E.a("//content.jwplatform.com/libraries/".concat(r,".js")).load().then(function(){var t=window.jwplayer.defaults.key,n=new p.b(t);n.error()||n.token()!==o.token()||(e.key=t,e.edition=n.edition(),e.error=n.error())}).catch(function(){})}return Promise.resolve()}function D(t){var e=t.get("advertising");return!(!e||!e.outstream)}var R=function(t){var e=t.get("skin")?t.get("skin").url:void 0;if("string"==typeof e&&!function(t){for(var e=document.styleSheets,n=0,r=e.length;n=4.4):null}},function(t,e,n){"use strict";var r,i=n(60),o=n(5),u=[],a=[],c={},s="screen"in window&&"orientation"in window.screen,l=o.OS.android&&o.Browser.chrome;function f(t,e){for(var n=e.length;n--;){var r=e[n];if(t.target===r.getContainer()){r.setIntersection(t);break}}}function d(){u.forEach(function(t){var e=t.model;if(!(e.get("audioMode")||!e.get("controls")||e.get("visibility")<.75)){var n=e.get("state"),r=window.screen.orientation.type,i="landscape-primary"===r||"landscape-secondary"===r;!i&&"paused"===n&&t.api.getFullscreen()?t.api.setFullscreen(!1):"playing"===n&&t.api.setFullscreen(i)}})}function p(){u.forEach(function(t){t.model.set("activeTab",Object(i.a)())})}function h(t,e){var n=e.indexOf(t);-1!==n&&e.splice(n,1)}document.addEventListener("visibilitychange",p),document.addEventListener("webkitvisibilitychange",p),l&&s&&window.screen.orientation.addEventListener("change",d),window.addEventListener("beforeunload",function(){document.removeEventListener("visibilitychange",p),document.removeEventListener("webkitvisibilitychange",p),l&&s&&window.screen.orientation.removeEventListener("change",d)}),e.a={add:function(t){u.push(t)},remove:function(t){h(t,u)},addWidget:function(t){a.push(t)},removeWidget:function(t){h(t,a)},size:function(){return u.length},observe:function(t){var e;e=window.IntersectionObserver,r||(r=new e(function(t){if(t&&t.length)for(var e=t.length;e--;){var n=t[e];f(n,u),f(n,a)}},{threshold:[0,.1,.2,.3,.4,.5,.6,.7,.8,.9,1]})),c[t.id]||(c[t.id]=!0,r.observe(t))},unobserve:function(t){r&&c[t.id]&&(delete c[t.id],r.unobserve(t))}}},function(t,e,n){"use strict";n.d(e,"a",function(){return f});var r=n(0),i=n(49),o=n(7),u=n(11);function a(t,e){for(var n=0;n
'),d=f.firstChild,p=d.firstChild,h=d.nextSibling;Object(u.d)([d,h],Object(r.k)({overflow:"auto"},a,s)),Object(u.d)(f,Object(r.k)({},a,s)),this.expandElement=d,this.expandChild=p,this.contractElement=h,this.hiddenElement=f,this.element=e,this.view=n,this.model=i,this.width=0,this.resized=!1,e.firstChild?e.insertBefore(f,e.firstChild):e.appendChild(f),e.addEventListener("scroll",l,!0),c.push(this),l()}var e,n,i;return e=t,(n=[{key:"destroy",value:function(){if(this.view){var t=c.indexOf(this);-1!==t&&c.splice(t,1),this.element.removeEventListener("scroll",l,!0),this.element.removeChild(this.hiddenElement),this.view=this.model=null}}}])&&a(e.prototype,n),i&&a(e,i),t}()},function(t,e,n){"use strict";n.r(e);var r=n(0),i=setTimeout;function o(){}function u(t){if(!(this instanceof u))throw new TypeError("Promises must be constructed via new");if("function"!=typeof t)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],d(t,this)}function a(t,e){for(;3===t._state;)t=t._value;0!==t._state?(t._handled=!0,u._immediateFn(function(){var n=1===t._state?e.onFulfilled:e.onRejected;if(null!==n){var r;try{r=n(t._value)}catch(t){return void s(e.promise,t)}c(e.promise,r)}else(1===t._state?c:s)(e.promise,t._value)})):t._deferreds.push(e)}function c(t,e){try{if(e===t)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var n=e.then;if(e instanceof u)return t._state=3,t._value=e,void l(t);if("function"==typeof n)return void d((r=n,i=e,function(){r.apply(i,arguments)}),t)}t._state=1,t._value=e,l(t)}catch(e){s(t,e)}var r,i}function s(t,e){t._state=2,t._value=e,l(t)}function l(t){2===t._state&&0===t._deferreds.length&&u._immediateFn(function(){t._handled||u._unhandledRejectionFn(t._value)});for(var e=0,n=t._deferreds.length;e2&&void 0!==arguments[2]?arguments[2]:[];if(O.a.debug)return t.apply(e||this,n);try{return t.apply(e||this,n)}catch(e){return new _(t.name,e)}},Error:_,Timer:x.a,log:D.a,genId:R.b,between:L.a,foreach:function(t,e){for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&e(n,t[n])},flashVersion:F.a,isIframe:F.m,indexOf:r.q,trim:A.i,pad:A.e,extension:A.a,hms:A.b,seconds:A.g,prefix:A.f,suffix:A.h,noop:function(){}}),q=0;function z(t,e){var n=new C.a(e);return n.on(P.hb,function(e){t._qoe.tick("ready"),e.setupTime=t._qoe.between("setup","ready")}),n.on("all",function(e,n){t.trigger(e,n)}),n}function V(t,e){var n=t.plugins;Object.keys(n).forEach(function(t){delete n[t]}),e.get("setupConfig")&&t.trigger("remove"),t.off(),e.playerDestroy(),e.getContainer().removeAttribute("data-jwplayer-id")}function Q(t){var e=++q,n=t.id||"player-".concat(e),i=new x.a,o={},u=z(this,t);i.tick("init"),t.setAttribute("data-jwplayer-id",n),Object.defineProperties(this,{id:{enumerable:!0,get:function(){return n}},uniqueId:{enumerable:!0,get:function(){return e}},plugins:{enumerable:!0,get:function(){return o}},_qoe:{enumerable:!0,get:function(){return i}},version:{enumerable:!0,get:function(){return w.a}},Events:{enumerable:!0,get:function(){return S.a}},utils:{enumerable:!0,get:function(){return B}},_:{enumerable:!0,get:function(){return r.g}}}),Object(r.k)(this,{_events:{},setup:function(e){return i.clear("ready"),i.tick("setup"),V(this,u),(u=z(this,t)).init(e,this),this.on(e.events,null,this)},remove:function(){return function(t){for(var e=v.a.length;e--;)if(v.a[e].uniqueId===t.uniqueId){v.a.splice(e,1);break}}(this),V(this,u),this},qoe:function(){var t=u.getItemQoe();return{setupTime:this._qoe.between("setup","ready"),firstFrame:t.getFirstFrame?t.getFirstFrame():null,player:this._qoe.dump(),item:t.dump()}},addCues:function(t){return Array.isArray(t)&&u.addCues(t),this},getAudioTracks:function(){return u.getAudioTracks()},getBuffer:function(){return u.get("buffer")},getCaptions:function(){return u.get("captions")},getCaptionsList:function(){return u.getCaptionsList()},getConfig:function(){return u.getConfig()},getContainer:function(){return u.getContainer()},getControls:function(){return u.get("controls")},getCues:function(){return u.get("cues")},getCurrentAudioTrack:function(){return u.getCurrentAudioTrack()},getCurrentCaptions:function(){return u.getCurrentCaptions()},getCurrentQuality:function(){return u.getCurrentQuality()},getCurrentTime:function(){return u.get("currentTime")},getDuration:function(){return u.get("duration")},getEnvironment:function(){return k},getFullscreen:function(){return u.get("fullscreen")},getHeight:function(){return u.getHeight()},getItemMeta:function(){return u.get("itemMeta")||{}},getMute:function(){return u.getMute()},getPlaybackRate:function(){return u.get("playbackRate")},getPlaylist:function(){return u.get("playlist")},getPlaylistIndex:function(){return u.get("item")},getPlaylistItem:function(t){if(!B.exists(t))return u.get("playlistItem");var e=this.getPlaylist();return e?e[t]:null},getPosition:function(){return u.get("position")},getProvider:function(){return u.getProvider()},getQualityLevels:function(){return u.getQualityLevels()},getSafeRegion:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return u.getSafeRegion(t)},getState:function(){return u.getState()},getStretching:function(){return u.get("stretching")},getViewable:function(){return u.get("viewable")},getVisualQuality:function(){return u.getVisualQuality()},getVolume:function(){return u.get("volume")},getWidth:function(){return u.getWidth()},setCaptions:function(t){return u.setCaptions(t),this},setConfig:function(t){return u.setConfig(t),this},setControls:function(t){return u.setControls(t),this},setCurrentAudioTrack:function(t){u.setCurrentAudioTrack(t)},setCurrentCaptions:function(t){u.setCurrentCaptions(t)},setCurrentQuality:function(t){u.setCurrentQuality(t)},setFullscreen:function(t){return u.setFullscreen(t),this},setMute:function(t){return u.setMute(t),this},setPlaybackRate:function(t){return u.setPlaybackRate(t),this},setPlaylistItem:function(t,e){return u.setPlaylistItem(t,e),this},setCues:function(t){return Array.isArray(t)&&u.setCues(t),this},setVolume:function(t){return u.setVolume(t),this},load:function(t,e){return u.load(t,e),this},play:function(t){return u.play(t),this},pause:function(t){return u.pause(t),this},playToggle:function(t){switch(this.getState()){case P.qb:case P.kb:return this.pause(t);default:return this.play(t)}},seek:function(t,e){return u.seek(t,e),this},playlistItem:function(t,e){return u.playlistItem(t,e),this},playlistNext:function(t){return u.playlistNext(t),this},playlistPrev:function(t){return u.playlistPrev(t),this},next:function(t){return u.next(t),this},castToggle:function(){return u.castToggle(),this},createInstream:function(){return u.createInstream()},skipAd:function(){return u.skipAd(),this},stop:function(){return u.stop(),this},resize:function(t,e){return u.resize(t,e),this},addButton:function(t,e,n,r,i){return u.addButton(t,e,n,r,i),this},removeButton:function(t){return u.removeButton(t),this},attachMedia:function(){return u.attachMedia(),this},detachMedia:function(){return u.detachMedia(),this},isBeforeComplete:function(){return u.isBeforeComplete()},isBeforePlay:function(){return u.isBeforePlay()}})}Object(r.k)(Q.prototype,{on:function(t,e,n){return S.c.call(this,t,e,n)},once:function(t,e,n){return S.d.call(this,t,e,n)},off:function(t,e,n){return S.b.call(this,t,e,n)},trigger:function(t,e){return(e=r.g.isObject(e)?Object(r.k)({},e):{}).type=t,O.a.debug?S.e.call(this,t,e):S.f.call(this,t,e)},getPlugin:function(t){return this.plugins[t]},addPlugin:function(t,e){this.plugins[t]=e,this.on("ready",e.addToPlayer),e.resize&&this.on("resize",e.resizeHandler)},registerPlugin:function(t,e,n){Object(y.b)(t,e,n)},getAdBlock:function(){return!1},playAd:function(t){},pauseAd:function(t){}}),n.p=Object(h.loadFrom)();var W=function(t){var e,n;if(t?"string"==typeof t?(e=X(t))||(n=document.getElementById(t)):"number"==typeof t?e=v.a[t]:t.nodeType&&(e=X((n=t).id||n.getAttribute("data-jwplayer-id"))):e=v.a[0],e)return e;if(n){var r=new Q(n);return v.a.push(r),r}return{registerPlugin:y.b}};function X(t){for(var e=0;e 120) { duration = -seekable_dur } + } + return duration + } + function get_duration_inf () { + return is_live() ? 1 / 0 : get_duration() + } + function is_live () { + var live, levels + try { + if (!(levels = hls.streamController.levels)) { return } + var loaded_lvl = levels.find(function (lvl) { return lvl.details }) + live = loaded_lvl && !!loaded_lvl.details.live + } catch (e) { hls_log('is_live failed with ' + e) } + return live + } + function get_buffered () { + var buf = video.buffered; var dur = video.duration + if (!buf || !buf.length || dur <= 0 || dur == Infinity) { return 0 } + return Math.min(buf.end(buf.length - 1) / dur, 1.0) + } + function set_buffered (buffered, pos, duration) { + if (buffered == _buffered && duration == _duration) { return } + _buffered = buffered + _this.trigger(jwe.JWPLAYER_MEDIA_BUFFER, { bufferPercent: buffered * 100, + position: pos, + duration: get_duration_inf() }) + } + function playback_complete () { + _this.setState('complete') + _this.trigger(jwe.JWPLAYER_MEDIA_COMPLETE) + _this.before_complete = false + } + var video_listeners = { + durationchange: function () { + _duration = get_duration() + set_buffered(get_buffered(), _position, _duration) + }, + ended: function () { + if (_this.state == 'idle' || _this.state == 'complete') { return } + _this.before_complete = true + _this.trigger(jwe.JWPLAYER_MEDIA_BEFORECOMPLETE) + if (_this.attached) { playback_complete() } + }, + error: function () { + _this.trigger(jwe.JWPLAYER_MEDIA_ERROR, { + message: 'Error loading media: File could not be played' }) + }, + loadstart: function () { video.setAttribute('jw-loaded', 'started') }, + loadeddata: function () { + video.setAttribute('jw-loaded', 'data') + if (!_this.supports_captions()) { return } + video.textTracks.onaddtrack = function () { + _this.renderNatively = true + _this.trigger('subtitlesTracks', { tracks: video.textTracks }) + } + // XXX pavelki: add checking of playlist + if (video.textTracks.length) { video.textTracks.onaddtrack() } + }, + loadedmetadata: function () { + if (video.muted) { + video.muted = false + video.muted = true + } + video.setAttribute('jw-loaded', 'meta') + _duration = get_duration() + _this.trigger(jwe.JWPLAYER_MEDIA_META, { duration: + get_duration_inf(), + height: video.videoHeight, + width: video.videoWidth }) + }, + canplay: function () { + can_play = true + _this.trigger(jwe.JWPLAYER_MEDIA_BUFFER_FULL) + }, + playing: function () { + _this.setState('playing') + if (!video.hasAttribute('jw-played')) { video.setAttribute('jw-played', '') } + if (video.hasAttribute('jw-gesture-required')) { + video.removeAttribute('jw-gesture-required') + video.removeAttribute('autoplay-failed') + } + _this.trigger(jwe.JWPLAYER_PROVIDER_FIRST_FRAME, {}) + }, + pause: function () { + if (_this.state == 'complete' || video.currentTime == video.duration) { return } + _this.setState('paused') + }, + seeking: function () { + if (!_this._in_seek) { + _this._in_seek = true + _this.trigger(jwe.JWPLAYER_MEDIA_SEEK, { position: _position, + offset: video.currentTime }) + } + }, + seeked: function () { + _this._in_seek = false + _this.trigger(jwe.JWPLAYER_MEDIA_SEEKED) + }, + progress: function () { + set_buffered(get_buffered(), _position, _duration) + }, + timeupdate: function () { + _duration = get_duration() + _position = _duration < 0 ? -(get_seekable_end() - video.currentTime) + : video.currentTime + + var a = { + position: _position, + duration: _duration, + currentTime: video.currentTime, + metadata: {currentTime: video.currentTime} + }; + set_buffered(get_buffered(), _position, _duration); + if (_this.state=='playing') + { + _this.trigger(jwe.JWPLAYER_MEDIA_TIME, a); + } + + // set_buffered(get_buffered(), _position, _duration) + // if (_this.state == 'playing') { + // _this.trigger(jwe.JWPLAYER_MEDIA_TIME, { position: _position, + // duration: get_duration_inf() }) + // } + } + } + function wrap_gen (e) { + return function () { + if (!_this.attached) { return } + video_listeners[e]() + } + } + for (var e in video_listeners) { video.addEventListener(e, wrap_gen(e), false) } + function scaled_number (num) { + if (num === undefined) { return '' } + if (!num) { return '0' } + var k = 1024 + var sizes = ['', 'K', 'M', 'G', 'T', 'P'] + var i = Math.floor(Math.log(num) / Math.log(k)) + num /= Math.pow(k, i) + if (num < 0.001) { return '0' } + if (num >= k - 1) { num = Math.trunc(num) } + var str = num.toFixed(num < 1 ? 3 : num < 10 ? 2 : num < 100 ? 1 : 0) + return str.replace(/\.0*$/, '') + sizes[i] + } + // XXX yurij: duplicate from videojs5-hlsjs to avoid deps + function level_label (level) { + if (level.height) { return level.height + 'p' } + if (level.width) { return Math.round(level.width * 9 / 16) + 'p' } + if (level.bitrate) { return scaled_number(level.bitrate) + 'bps' } + return 0 + } + function get_levels () { + var levels = hls.levels || []; var res = [] + // level 0 mimics native jw's hls provider behavior + if (levels.length > 1) { res.push({ label: 'Auto' }) } + levels.forEach(function (level) { + res.push({ bitrate: level.bitrate, + height: level.height, + label: level_label(level), + width: level.width }) + }) + return res + } + function get_level (level) { + var levels = hls.levels || [] + level = level || hls.currentLevel + return { + // level 0 is dummy for 'Auto' option in jwplayer's UI + jw: hls.manual_level == -1 || levels.length < 2 ? 0 : level + 1, + real: levels.length < 2 ? 0 : level + 1 + } + } + hls.on(Hls.Events.ERROR, function (event, data) { + if (!data.fatal) { return } + var msg + switch (data.details) { + case Hls.ErrorDetails.MANIFEST_LOAD_ERROR: + case Hls.ErrorDetails.MANIFEST_LOAD_TIMEOUT: + msg = 'Cannot load M3U8: ' + data.response.statusText + break + default: + msg = 'Error loading media: ' + data.details + break + } + + var a = {key: 'cantPlayVideo', code: data.details, recoverable: false, stalling: false, suppressLevel: false, fatal: true, error: data}; + + _this.trigger(jwe.JWPLAYER_MEDIA_ERROR, a) + + // var seen = []; + // + // var raw_error = JSON.stringify(data, function(key, val) { + // if (typeof val == "object") { + // if (seen.indexOf(val) >= 0) + // return; + // seen.push(val) + // } + // return val; + // }); + // + // var time = getPlaying(video_id, episode_id); + // + // $.ajax({ + // type: 'POST', + // url: '/play-trunk-error', + // data: { + // 'video_id': video_id, + // 'episode_id': episode_id, + // 'message': msg, + // 'raw_error' : raw_error, + // 'time': parseInt(time) + // }, + // dataType: 'json', + // success: function (data) { + // }, + // error: function (data) { + // } + // }); + }) + hls.on(Hls.Events.MANIFEST_LOADED, function () { + _this.trigger(jwe.JWPLAYER_MEDIA_LEVELS, { + currentQuality: get_level().jw, + levels: get_levels() + }) + var levels; var is_video = 0 + if (!(levels = hls.levels)) { return } + levels.forEach(function (level) { + is_video += +!!(level.videoCodec || !level.audioCodec && + (level.bitrate > 64000 || level.width || level.height)) + }) + _this.trigger(jwe.JWPLAYER_MEDIA_TYPE, { mediaType: is_video + ? 'video' : 'audio' }) + }) + hls.on(Hls.Events.LEVEL_SWITCH, function (e, data) { + var levels = get_levels(); var level_id = get_level(data.level) + _this.trigger(jwe.JWPLAYER_MEDIA_LEVEL_CHANGED, { + currentQuality: level_id.jw, + levels: levels + }) + var level = levels[level_id.real] + visual_quality.level = level + visual_quality.level.index = level_id.real + visual_quality.level.label = hls.manual_level == -1 && levels.length > 1 + ? 'auto' : level.label + visual_quality.reason = visual_quality.reason || 'auto' + _this.trigger('visualQuality', visual_quality) + visual_quality.reason = '' + }) + this.init = function (item) { + try_play = false + video.setAttribute('jw-loaded', 'init') + } + this.load = function (item) { + if (!this.attached) { return } + var newsource = get_default_src(item.sources).file + var video_state = video.getAttribute('jw-loaded') + var hq = this.hls_queued; var played = video.hasAttribute('jw-played') + if (!_is_mobile || played) { + // don't change state on mobile before user initiates playback + this.setState('loading') + } + hq.seek = Math.max(item.starttime - (hq.rw_sec || 0), 0) + if (this.hls_state != 'ready' || (this.source || '') != newsource || + ['init', 'started'].includes(video_state)) { + var sc + try_play = false + video.load() + hls.stopLoad(hls.media && this.hls_state == 'ready' && + video_state == 'init') + hls_load(this.source = newsource) + video.setAttribute('jw-loaded', 'init') + } else { hls_play() } + if (_is_mobile && !played) { + if (!try_play && (!_is_mobile.is_ios || can_play)) { + try_play = true + can_play = false + video_play() + } + if (!video.paused && this.state != 'playing') { this.setState('loading') } + } + } + this.play = function () { hls_play() } + this.pause = function () { + video.pause() + _this.setState('paused') + } + this.stop = function () { + hls.stopLoad() + _this.setState('idle') + } + this.volume = function (vol) { video.volume = Math.min(vol / 100, 1.0) } + this.mute = function (state) { video.muted = !!state } + this.seek = function (pos) { + this._in_seek = true + if (this.hls_state == 'ready') { + var sv = video.currentTime + video.currentTime = pos + this.trigger(jwe.JWPLAYER_MEDIA_SEEK, { position: sv, offset: pos }) + } else { this.hls_queued.seek = pos } + } + // XXX arik: todo, without it video resize will be wrong. + // eg. http://www.ozee.com/shows/muddha-mandaram#hola_mode=cdn&hola_zone=ozee_hap + this.resize = function (width, height, stretching) {} + this.remove = function () { + this.in_container = false + hls.stopLoad() + this.source = undefined + if (container === video.parentNode) { container.removeChild(video) } + } + this.destroy = function () { + for (var e in video_listeners) { video.removeEventListener(e, video_listeners[e], false) } + this.removeAllListeners() + } + this.setVisibility = function (state) { + container.style.visibility = state ? 'visible' : '' + container.style.opacity = state ? 1 : 0 + } + this.setFullscreen = function () { return false } + this.getFullscreen = empty_fn('getFullscreen') + this.getContainer = function () { return container } + this.setContainer = function (element) { + container = element + container.appendChild(video) + this.in_container = true + } + hls.manual_level = -1 + this.setCurrentQuality = function (level) { + if (level == hls.manual_level + 1) { return } + hls.manual_level = level - 1 + if (!hls.hola_adaptive) { hls.loadLevel = hls.manual_level } + _this.trigger(jwe.JWPLAYER_MEDIA_LEVEL_CHANGED, + { currentQuality: level, levels: get_levels() }) + visual_quality.reason = 'api' + } + this.getName = function () { return { name: 'hola/hls' } } + this.get_position = function () { return video.currentTime } + this.getQualityLevels = function () { return get_levels() } + this.getCurrentQuality = function () { return get_level(hls.loadLevel).jw } + this.getAudioTracks = empty_fn('getAudioTracks') + this.getCurrentAudioTrack = empty_fn('getCurrentAudioTrack') + this.setCurrentAudioTrack = empty_fn('setCurrentAudioTrack') + this.checkComplete = function () { return !!this.before_complete } + this.setControls = empty_fn('setControls') + this.attachMedia = function () { + if (this.before_complete) { return playback_complete() } + if (this.ad_count) { hls_log('jwprovider attach inside ad ' + this.ad_count) } + this.attached = true + hls.attachMedia(video) + } + this.detachMedia = function () { + hls.trigger(Hls.Events.BUFFER_RESET) + hls.detachMedia() + if (this.level_cb) { + hls.off(Hls.Events.LEVEL_LOADED, this.level_cb) + this.level_cb = undefined + } + // XXX pavelki: hack to remove pending segments + try{ + delete hls.bufferController.segments + }catch(err){ + } + + this.attached = false + return video + } + this.setState = function (state) { + var oldState = this.state || 'idle' + this.state = state + if (state == oldState) { return } + this.trigger(jwe.JWPLAYER_PLAYER_STATE, { newstate: state }) + } + this.sendMediaType = function (levels) { + var is_audio = ['oga', 'aac', 'mp3', 'mpeg', 'vorbis'] + .includes(levels[0].type) + this.trigger(jwe.JWPLAYER_MEDIA_TYPE, { mediaType: is_audio + ? 'audio' : 'video' }) + } + } + + E.getName = function () { return { name: 'hola/hls' } } + + // XXX yurij: copied from zjwplayer3.js to not depend on our code + function get_player_instances () { + var jwplayer = E.jwplayer || window.jwplayer + var i = 0; var res = []; var jw + // XXX marka/vadiml: a real instance will contain pause(), otherwise it + // will be {registerPlugin: ...} with anything the customer adds + while ((jw = jwplayer(i++)) && jw.pause) { res.push(jw) } + return res + } + + function src_supported (src) { + if (src.type == 'hls') { return true } + return (src.file || '').match(/\.m3u8$/) + } + + E.supports = function (src) { + var Hls = E.Hls || window.Hls + var is_ad = get_player_instances().every(function (j) { + // XXX yurij: jw.getPlaylist returns playlist item on early call + var pl = j.getPlaylist() + return (pl.every ? pl : [{ sources: [pl] }]).every(function (p) { + // XXX pavlo: playlist item can be w/o sources/allSources + return (p.allSources || p.sources || [{ file: p.file }]) + .every(function (s) { return s.file != src.file }) + }) + }) + if (is_ad) // XXX yurij: we are not supporting adaptive ads + { return false } + return !E.disabled && src_supported(src) && Hls && Hls.isSupported() + } + + E.attach = function () { + var jwplayer = E.jwplayer || window.jwplayer + E.disabled = false + if (!provider_attached) { + provider_attached = true + // XXX arik: unregister on error/fallback + jwplayer.api.registerProvider(this) + } + } + + E.detach = function (hp) { + // we don't remove provider from list, just set it as disabled so it will + // return false in supports() + E.disabled = true + if (!hp || !hp.attached) { return } + hp.setState('idle') + hp.detachMedia() + } + + // XXX vadiml copied from loader.js&zjwplayer3.js to not depend on our code. + // For use by HolaCDN Onboarding Tool extension + E.reload_jwplayer_instances = function () { + get_player_instances().forEach(function (jw) { + var c = jw.getConfig() + if (!c) { return } + // XXX marka: JW removes conf.advertising.client, try to restore it + if (c.advertising && !c.advertising.client && c.plugins) { + for (var url in c.plugins) { + if (c.plugins[url] !== c.advertising) { continue } + var m = url.match(/\/(\w+)\.js$/) + c.advertising.client = m && m[1] + break + } + } + jw.setup(c) + }) + } + + E.VERSION = '0.0.79' + }, { 'eventemitter3': 1 }] }, {}, [2])(2) +}) +// # sourceMappingURL=jwplayer.hlsjs.js.map diff --git a/resources/views/core/base/columns/relationship.blade.php b/resources/views/core/base/columns/relationship.blade.php new file mode 100644 index 0000000..e7b690a --- /dev/null +++ b/resources/views/core/base/columns/relationship.blade.php @@ -0,0 +1,23 @@ +@php + $column['value'] = $column['value'] ?? data_get($entry, $column['name']); + $column['escaped'] = $column['escaped'] ?? true; + $column['text'] = $column['default'] ?? '-'; + + if ($column['value'] instanceof \Closure) { + $column['value'] = $column['value']($entry); + } + + if (!empty($column['value'])) { + $column['text'] = isset($column['value']->name) ? $column['value']->name : $column['value']->pluck('name')->implode(', '); + } +@endphp + + + @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start') + @if ($column['escaped']) + {{ $column['text'] }} + @else + {!! $column['text'] !!} + @endif + @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end') + diff --git a/resources/views/core/base/dashboard.blade.php b/resources/views/core/base/dashboard.blade.php new file mode 100644 index 0000000..c939167 --- /dev/null +++ b/resources/views/core/base/dashboard.blade.php @@ -0,0 +1,199 @@ +@extends(backpack_view('blank')) + +@php + $widgets['before_content'] = [ + [ + 'type' => 'alert', + 'class' => 'alert alert-dark mb-2 col-12', + 'heading' => 'VsMovCMS - Tạo website xem phim miễn phí vĩnh viễn', + 'content' => + ' + Phiên bản: ' . + config('vsmov.version') . + '
+ Trang chủ: VsMovCMS.Com
+ Dữ liệu phim miễn phí: VsMov.COM + ', + 'close_button' => true, // show close button or not + ], + ]; +@endphp + +@section('content') + + + + + + +
+
+
+ + {{ $count_movies }} + Tổng số phim +
+
+ +
+
+ + {{ $count_episodes }} + Tổng số tập +
+
+ +
+
+ + {{ $count_episodes_error }} + Tập lỗi +
+
+ +
+
+ + {{ $count_users }} + Users +
+
+ +
+
+ + {{ $count_themes }} + Giao diện +
+
+ +
+
+ + {{ count(config('plugins', [])) }} + Plugins +
+
+
+
+
+ + + + + + + + @foreach ($top_view_day as $movie) + + + + + @endforeach + +
TOP NGÀY
{{ $movie->name }} {{ $movie->view_day }}
+
+
+ + + + + + + + @foreach ($top_view_week as $movie) + + + + + @endforeach + +
TOP TUẦN
{{ $movie->name }} {{ $movie->view_week }}
+
+
+ + + + + + + + @foreach ($top_view_month as $movie) + + + + + @endforeach + +
TOP THÁNG
{{ $movie->name }} {{ $movie->view_month }}
+
+
+@endsection diff --git a/resources/views/core/base/fields/checklist.blade.php b/resources/views/core/base/fields/checklist.blade.php new file mode 100644 index 0000000..85fe7a3 --- /dev/null +++ b/resources/views/core/base/fields/checklist.blade.php @@ -0,0 +1,109 @@ + +@php +$key_attribute = (new $field['model']())->getKeyName(); +$field['attribute'] = $field['attribute'] ?? (new $field['model']())->identifiableAttribute(); +$field['number_of_columns'] = $field['number_of_columns'] ?? 3; + +// calculate the checklist options +if (!isset($field['options'])) { + $field['options'] = $field['model'] + ::all() + ->pluck($field['attribute'], $key_attribute) + ->toArray(); +} else { + $field['options'] = call_user_func($field['options'], $field['model']::query()); +} + +// calculate the value of the hidden input +$field['value'] = old_empty_or_null($field['name'], []) ?? ($field['value'] ?? ($field['default'] ?? [])); +if (!empty($field['value'])) { + if (is_a($field['value'], \Illuminate\Support\Collection::class)) { + $field['value'] = $field['value']->pluck($key_attribute)->toArray(); + } elseif (is_string($field['value'])) { + $field['value'] = json_decode($field['value']); + } +} + +// define the init-function on the wrapper +$field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitChecklist'; +@endphp + +@include('crud::fields.inc.wrapper_start') + +@include('crud::fields.inc.translatable_icon') + + + +
+ @foreach ($field['options'] as $key => $option) +
+
+ +
+
+ @endforeach +
+ +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') + + +{{-- ########################################## --}} +{{-- Extra CSS and JS for this particular field --}} +{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}} +{{-- FIELD JS - will be loaded in the after_scripts section --}} +@push('crud_fields_scripts') + @loadOnce('bpFieldInitChecklist') + + @endLoadOnce +@endpush +{{-- End of Extra CSS and JS --}} +{{-- ########################################## --}} diff --git a/resources/views/core/base/fields/ckfinder.blade.php b/resources/views/core/base/fields/ckfinder.blade.php new file mode 100644 index 0000000..8b20a91 --- /dev/null +++ b/resources/views/core/base/fields/ckfinder.blade.php @@ -0,0 +1,76 @@ + +@include('crud::fields.inc.wrapper_start') +@php +$field['has_preview'] = isset($field['has_preview']) ? $field['has_preview'] : false; +$field['preview']['width'] = isset($field['preview']['width']) ? $field['preview']['width'] : '90%'; +$field['preview']['height'] = isset($field['preview']['height']) ? $field['preview']['height'] : '90%'; +@endphp + +
+ + + + +
+@if ($field['has_preview'] && old($field['name'], isset($entry) ? $entry->{$field['name']} : '')) + +@endif + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') + +@if ($crud->fieldTypeNotLoaded($field)) + @php + $crud->markFieldTypeAsLoaded($field); + @endphp + + {{-- FIELD EXTRA CSS --}} + {{-- push things in the after_styles section --}} + @push('crud_fields_styles') + + @endpush + + {{-- FIELD EXTRA JS --}} + {{-- push things in the after_scripts section --}} + @push('crud_fields_scripts') + @include('ckfinder::setup') + + @endpush +@endif diff --git a/resources/views/core/base/fields/fields_option.blade.php b/resources/views/core/base/fields/fields_option.blade.php new file mode 100644 index 0000000..60d023a --- /dev/null +++ b/resources/views/core/base/fields/fields_option.blade.php @@ -0,0 +1,91 @@ +@php +$value = isset($field) ? old_empty_or_null($field['name'], '') ?? ($field['value'] ?? null) : null; +@endphp + +@php +$progress = [ + 'episodes' => 'Tập mới', + 'status' => 'Trạng thái phim', + 'episode_time' => 'Thời lượng tập phim', + 'episode_current' => 'Số tập phim hiện tại', + 'episode_total' => 'Tổng số tập phim', +]; + +$info = [ + 'name' => 'Tên phim', + 'origin_name' => 'Tên gốc phim', + 'content' => 'Mô tả nội dung phim', + 'thumb_url' => 'Ảnh Thumb', + 'poster_url' => 'Ảnh Poster', + 'trailer_url' => 'Trailer URL', + 'quality' => 'Chất lượng phim', + 'language' => 'Ngôn ngữ', + 'notify' => 'Nội dung thông báo', + 'showtimes' => 'Giờ chiếu phim', + 'publish_year' => 'Năm xuất bản', + 'is_shown_in_theater' => 'Đánh dấu phim chiếu rạp', + 'is_copyright' => 'Đánh dấu có bản quyền', +]; + +$relations = [ + 'type' => 'Định dạng phim', + 'actors' => 'Diễn viên', + 'directors' => 'Đạo diễn', + 'categories' => 'Thể loại', + 'regions' => 'Khu vực', + 'tags' => 'Từ khóa', + 'studios' => 'Studio', +]; +@endphp + +
+
+
+ + +
+ @foreach ($progress as $key => $option) +
+ + +
+ @endforeach +
+
+
+ + +
+ @foreach ($info as $key => $option) +
+ + +
+ @endforeach +
+
+
+ + +
+ @foreach ($relations as $key => $option) +
+ + +
+ @endforeach +
+ +
+ +{{-- FIELD JS - will be loaded in the after_scripts section --}} +@push('crud_fields_scripts') + +@endpush diff --git a/resources/views/core/base/fields/page_or_link.blade.php b/resources/views/core/base/fields/page_or_link.blade.php new file mode 100644 index 0000000..0a65e98 --- /dev/null +++ b/resources/views/core/base/fields/page_or_link.blade.php @@ -0,0 +1,131 @@ +{{-- PAGE OR LINK field --}} +{{-- Used in Backpack\MenuCRUD --}} + + + +@include('crud::fields.inc.wrapper_start') + + @include('crud::fields.inc.translatable_icon') + +
+ {{-- hidden placeholders for content --}} + + +
+ {{-- type select --}} + +
+
+ {{-- internal link input --}} + + + {{-- external link input --}} + +
+
+ + {{-- HINT --}} + @if (isset($field['hint'])) +

{!! $field['hint'] !!}

+ @endif + +@include('crud::fields.inc.wrapper_end') + + +{{-- ########################################## --}} +{{-- Extra CSS and JS for this particular field --}} +{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}} +@if ($crud->fieldTypeNotLoaded($field)) + @php + $crud->markFieldTypeAsLoaded($field); + @endphp + + {{-- FIELD JS - will be loaded in the after_scripts section --}} + @push('crud_fields_scripts') + + @endpush + +@endif +{{-- End of Extra CSS and JS --}} +{{-- ########################################## --}} diff --git a/resources/views/core/base/fields/select2_from_array.blade.php b/resources/views/core/base/fields/select2_from_array.blade.php new file mode 100644 index 0000000..891f9fa --- /dev/null +++ b/resources/views/core/base/fields/select2_from_array.blade.php @@ -0,0 +1,44 @@ + +@include('crud::fields.inc.wrapper_start') +@php +$field['allows_multiple'] = $field['allows_multiple'] ?? false; +$field['options'] = $field['options'] ?? []; +$field['value'] = $field['value'] ?? []; + +@endphp + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') + +@if ($crud->fieldTypeNotLoaded($field)) + @php + $crud->markFieldTypeAsLoaded($field); + @endphp + + {{-- FIELD EXTRA CSS --}} + {{-- push things in the after_styles section --}} + @push('crud_fields_styles') + + @endpush + + {{-- FIELD EXTRA JS --}} + {{-- push things in the after_scripts section --}} + @push('crud_fields_scripts') + + @endpush +@endif diff --git a/resources/views/core/base/fields/select2_relationship_tags.blade.php b/resources/views/core/base/fields/select2_relationship_tags.blade.php new file mode 100644 index 0000000..01969bd --- /dev/null +++ b/resources/views/core/base/fields/select2_relationship_tags.blade.php @@ -0,0 +1,48 @@ + +@include('crud::fields.inc.wrapper_start') +@php +$key_attribute = (new $field['model']())->getKeyName(); +$field['attribute'] = $field['attribute'] ?? (new $field['model']())->identifiableAttribute(); + +$selected = $field['model'] + ::whereIn('id', old($field['name'], isset($field['value']) ? $field['value']->pluck('id')->toArray() : [])) + ->pluck($field['attribute'], $key_attribute) + ->toArray(); +@endphp + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') + +@if ($crud->fieldTypeNotLoaded($field)) + @php + $crud->markFieldTypeAsLoaded($field); + @endphp + + {{-- FIELD EXTRA CSS --}} + {{-- push things in the after_styles section --}} + @push('crud_fields_styles') + + @endpush + + {{-- FIELD EXTRA JS --}} + {{-- push things in the after_scripts section --}} + @push('crud_fields_scripts') + + @endpush +@endif diff --git a/resources/views/core/base/fields/select2_tags.blade.php b/resources/views/core/base/fields/select2_tags.blade.php new file mode 100644 index 0000000..fd39764 --- /dev/null +++ b/resources/views/core/base/fields/select2_tags.blade.php @@ -0,0 +1,44 @@ + +@include('crud::fields.inc.wrapper_start') + +@php +$selected = $field['value'] ?? []; +@endphp + + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') + +@if ($crud->fieldTypeNotLoaded($field)) + @php + $crud->markFieldTypeAsLoaded($field); + @endphp + + {{-- FIELD EXTRA CSS --}} + {{-- push things in the after_styles section --}} + @push('crud_fields_styles') + + @endpush + + {{-- FIELD EXTRA JS --}} + {{-- push things in the after_scripts section --}} + @push('crud_fields_scripts') + + @endpush +@endif diff --git a/resources/views/core/base/fields/select_from_table.blade.php b/resources/views/core/base/fields/select_from_table.blade.php new file mode 100644 index 0000000..b3f7e7a --- /dev/null +++ b/resources/views/core/base/fields/select_from_table.blade.php @@ -0,0 +1,40 @@ +@php +$field['allows_null'] = $field['allows_null'] ?? $crud->model::isColumnNullable($field['name']); +$field['value'] = old_empty_or_null($field['name'], '') ?? ($field['value'] ?? ($field['default'] ?? '')); +$field['multiple'] = $field['allows_multiple'] ?? ($field['multiple'] ?? false); +$field['options']['display_by'] = isset($field['options']['display_by']) ? $field['options']['display_by'] : 'name'; +$field['options']['value_by'] = isset($field['options']['value_by']) ? $field['options']['value_by'] : 'id'; +$options = \DB::table($field['options']['table']) + ->pluck($field['options']['display_by'], $field['options']['value_by']) + ->toArray(); +@endphp + +@include('crud::fields.inc.wrapper_start') + +@include('crud::fields.inc.translatable_icon') +@if ($field['multiple']) + +@endif + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') diff --git a/resources/views/core/base/fields/select_theme.blade.php b/resources/views/core/base/fields/select_theme.blade.php new file mode 100644 index 0000000..f4a16ac --- /dev/null +++ b/resources/views/core/base/fields/select_theme.blade.php @@ -0,0 +1,30 @@ +@php +$field['value'] = old_empty_or_null($field['name'], '') ?? ($field['value'] ?? ($field['default'] ?? '')); +$field['multiple'] = $field['allows_multiple'] ?? ($field['multiple'] ?? false); +$options = config('themes', []); +@endphp + +@include('crud::fields.inc.wrapper_start') + +@include('crud::fields.inc.translatable_icon') +@if ($field['multiple']) + +@endif + + + +{{-- HINT --}} +@if (isset($field['hint'])) +

{!! $field['hint'] !!}

+@endif +@include('crud::fields.inc.wrapper_end') diff --git a/resources/views/core/base/fields/update_fields_option.blade.php b/resources/views/core/base/fields/update_fields_option.blade.php new file mode 100644 index 0000000..bb9b76c --- /dev/null +++ b/resources/views/core/base/fields/update_fields_option.blade.php @@ -0,0 +1,91 @@ +@php +$value = isset($field) ? old_empty_or_null($field['name'], '') ?? ($field['value'] ?? null) : null; +@endphp + +@php +$progress = [ + 'episodes' => 'Tập mới', + 'status' => 'Trạng thái phim', + 'episode_time' => 'Thời lượng tập phim', + 'episode_current' => 'Số tập phim hiện tại', + 'episode_total' => 'Tổng số tập phim', +]; + +$info = [ + 'name' => 'Tên phim', + 'origin_name' => 'Tên gốc phim', + 'content' => 'Mô tả nội dung phim', + 'thumb_url' => 'Ảnh Thumb', + 'poster_url' => 'Ảnh Poster', + 'trailer_url' => 'Trailer URL', + 'quality' => 'Chất lượng phim', + 'language' => 'Ngôn ngữ', + 'notify' => 'Nội dung thông báo', + 'showtimes' => 'Giờ chiếu phim', + 'publish_year' => 'Năm xuất bản', + 'is_shown_in_theater' => 'Đánh dấu phim chiếu rạp', + 'is_copyright' => 'Đánh dấu có bản quyền', +]; + +$relations = [ + 'type' => 'Định dạng phim', + 'actors' => 'Diễn viên', + 'directors' => 'Đạo diễn', + 'categories' => 'Thể loại', + 'regions' => 'Khu vực', + 'tags' => 'Từ khóa', + 'studios' => 'Studio', +]; +@endphp + +
+
+
+ + +
+ @foreach ($progress as $key => $option) +
+ + +
+ @endforeach +
+
+
+ + +
+ @foreach ($info as $key => $option) +
+ + +
+ @endforeach +
+
+
+ + +
+ @foreach ($relations as $key => $option) +
+ + +
+ @endforeach +
+ +
+ +{{-- FIELD JS - will be loaded in the after_scripts section --}} +@push('after_scripts') + +@endpush diff --git a/resources/views/core/base/inc/main_header.blade.php b/resources/views/core/base/inc/main_header.blade.php new file mode 100644 index 0000000..f55ea0d --- /dev/null +++ b/resources/views/core/base/inc/main_header.blade.php @@ -0,0 +1,15 @@ +
+ + + + {!! setting('site_logo') ?? config('backpack.base.project_logo') !!} +
v{{ config('vsmov.version') }}
+
+ + + @include(backpack_view('inc.menu')) +
diff --git a/resources/views/core/base/inc/sidebar_content.blade.php b/resources/views/core/base/inc/sidebar_content.blade.php new file mode 100644 index 0000000..423fbe7 --- /dev/null +++ b/resources/views/core/base/inc/sidebar_content.blade.php @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + +@foreach (config('plugins', []) as $plugin) + @if (count($plugin['entries'] ?? []) > 1) + + @else + @foreach ($plugin['entries'] ?? [] as $entry) + + @endforeach + @endif +@endforeach + +@if (backpack_user()->hasRole('Admin')) + + +@endif diff --git a/resources/views/core/base/inc/topbar_right_content.blade.php b/resources/views/core/base/inc/topbar_right_content.blade.php new file mode 100644 index 0000000..3cefe2a --- /dev/null +++ b/resources/views/core/base/inc/topbar_right_content.blade.php @@ -0,0 +1,13 @@ + + + diff --git a/resources/views/core/crud/buttons/bulk_delete.blade.php b/resources/views/core/crud/buttons/bulk_delete.blade.php new file mode 100644 index 0000000..5479b8a --- /dev/null +++ b/resources/views/core/crud/buttons/bulk_delete.blade.php @@ -0,0 +1,104 @@ +@if ($crud->hasAccess('bulkDelete') && $crud->get('list.bulkActions')) + {{ trans('backpack::crud.delete') }} +@endif + +@push('after_scripts') + +@endpush diff --git a/resources/views/core/crud/filters/select2.blade.php b/resources/views/core/crud/filters/select2.blade.php new file mode 100644 index 0000000..8e7f313 --- /dev/null +++ b/resources/views/core/crud/filters/select2.blade.php @@ -0,0 +1,140 @@ +{{-- Select2 Backpack CRUD filter --}} + + +{{-- ########################################### --}} +{{-- Extra CSS and JS for this particular filter --}} + +{{-- FILTERS EXTRA CSS --}} +{{-- push things in the after_styles section --}} + +@push('crud_list_styles') + {{-- include select2 css --}} + + + +@endpush + + +{{-- FILTERS EXTRA JS --}} +{{-- push things in the after_scripts section --}} + +@push('crud_list_scripts') + {{-- include select2 js --}} + + @if (app()->getLocale() !== 'en') + + @endif + + +@endpush +{{-- End of Extra CSS and JS --}} +{{-- ########################################## --}} diff --git a/resources/views/core/crud/filters/simple.blade.php b/resources/views/core/crud/filters/simple.blade.php new file mode 100644 index 0000000..82dedea --- /dev/null +++ b/resources/views/core/crud/filters/simple.blade.php @@ -0,0 +1,72 @@ +{{-- Simple Backpack CRUD filter --}} + + + +{{-- ########################################### --}} +{{-- Extra CSS and JS for this particular filter --}} + +{{-- FILTERS EXTRA CSS --}} +{{-- push things in the after_styles section --}} + +{{-- @push('crud_list_styles') + no css +@endpush --}} + + +{{-- FILTERS EXTRA JS --}} +{{-- push things in the after_scripts section --}} + +@push('crud_list_scripts') + +@endpush +{{-- End of Extra CSS and JS --}} +{{-- ########################################## --}} diff --git a/resources/views/core/movies/columns/column_movie_info.blade.php b/resources/views/core/movies/columns/column_movie_info.blade.php new file mode 100644 index 0000000..c28650e --- /dev/null +++ b/resources/views/core/movies/columns/column_movie_info.blade.php @@ -0,0 +1,40 @@ +@php +$name = data_get($entry, $column['name']); +$origin_name = data_get($entry, $column['origin_name']); +$publish_year = data_get($entry, $column['publish_year']); +$episode_current = data_get($entry, $column['episode_current']); +$status = data_get($entry, $column['status']); +$movie_type = data_get($entry, $column['movie_type']); +$config_show_type = [ + 'single' => [ + 'class' => 'bg-secondary', + 'label' => 'Phim lẻ', + ], + 'series' => [ + 'class' => 'bg-primary', + 'label' => 'Phim bộ', + ], +]; +$config_show_status = [ + 'trailer' => [ + 'class' => 'bg-warning', + 'label' => 'Trailer', + ], + 'ongoing' => [ + 'class' => 'bg-info', + 'label' => 'Đang chiếu', + ], + 'completed' => [ + 'class' => 'bg-success', + 'label' => 'Hoàn thành', + ], +]; +@endphp +
+ @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_start') +
{{ $name }} [{{ $publish_year }}]
+
({{ $origin_name }}) [{{ $episode_current }}]
+
{{ $config_show_type[$movie_type]['label'] }}
+
{{ $config_show_status[$status]['label'] }}
+ @includeWhen(!empty($column['wrapper']), 'crud::columns.inc.wrapper_end') +
diff --git a/resources/views/core/movies/create.blade.php b/resources/views/core/movies/create.blade.php new file mode 100644 index 0000000..6b60567 --- /dev/null +++ b/resources/views/core/movies/create.blade.php @@ -0,0 +1,56 @@ +@extends(backpack_view('blank')) + +@php +$defaultBreadcrumbs = [ + trans('backpack::crud.admin') => url(config('backpack.base.route_prefix'), 'dashboard'), + $crud->entity_name_plural => url($crud->route), + trans('backpack::crud.add') => false, +]; + +// if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs +$breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs; +@endphp + +@section('header') +
+

+ {!! $crud->getHeading() ?? $crud->entity_name_plural !!} + {!! $crud->getSubheading() ?? trans('backpack::crud.add') . ' ' . $crud->entity_name !!}. + + @if ($crud->hasAccess('list')) + + {{ trans('backpack::crud.back_to_all') }} + {{ $crud->entity_name_plural }} + @endif +

+
+@endsection + +@section('content') +
+
+ + + @include('crud::inc.grouped_errors') + +
hasUploadFields('create')) enctype="multipart/form-data" @endif> + {!! csrf_field() !!} + + @if (view()->exists('vendor.backpack.crud.form_content')) + @include('vendor.backpack.crud.form_content', [ + 'fields' => $crud->fields(), + 'action' => 'create', + ]) + @else + @include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'create']) + @endif + +
{{ json_encode(Assets::loaded()) }}
+ + @include('crud::inc.form_save_buttons') +
+
+
+@endsection diff --git a/resources/views/core/movies/edit.blade.php b/resources/views/core/movies/edit.blade.php new file mode 100644 index 0000000..d1783c6 --- /dev/null +++ b/resources/views/core/movies/edit.blade.php @@ -0,0 +1,71 @@ +@extends(backpack_view('blank')) + +@php + $defaultBreadcrumbs = [ + trans('backpack::crud.admin') => backpack_url('dashboard'), + $crud->entity_name_plural => url($crud->route), + trans('backpack::crud.edit') => false, + ]; + + // if breadcrumbs aren't defined in the CrudController, use the default breadcrumbs + $breadcrumbs = $breadcrumbs ?? $defaultBreadcrumbs; +@endphp + +@section('header') +
+

+ {!! $crud->getHeading() ?? $crud->entity_name_plural !!} + {!! $crud->getSubheading() ?? trans('backpack::crud.edit').' '.$crud->entity_name !!}. + + @if ($crud->hasAccess('list')) + {{ trans('backpack::crud.back_to_all') }} {{ $crud->entity_name_plural }} + @endif +

+
+@endsection + +@section('content') +
+
+ + + @include('crud::inc.grouped_errors') + +
hasUploadFields('update', $entry->getKey())) + enctype="multipart/form-data" + @endif + > + {!! csrf_field() !!} + {!! method_field('PUT') !!} + + @if ($crud->model->translationEnabled()) +
+ +
+ + +
+
+ @endif + + @if(view()->exists('vendor.backpack.crud.form_content')) + @include('vendor.backpack.crud.form_content', ['fields' => $crud->fields(), 'action' => 'edit']) + @else + @include('crud::form_content', ['fields' => $crud->fields(), 'action' => 'edit']) + @endif + +
{{ json_encode(Assets::loaded()) }}
+ @include('crud::inc.form_save_buttons') +
+
+
+@endsection + diff --git a/resources/views/core/movies/inc/episode.blade.php b/resources/views/core/movies/inc/episode.blade.php new file mode 100644 index 0000000..a7a32ed --- /dev/null +++ b/resources/views/core/movies/inc/episode.blade.php @@ -0,0 +1,435 @@ +episodes : [])); +?> +
+
+
+ + + + +
+ +
+ + + +
+ +
+ @if (count($episodes)) + @foreach ($episodes->groupBy('server') as $server => $data) +
+
+ + + + + + + + + + + + @foreach ($data->sortBy('name', SORT_NATURAL)->groupBy('name') as $sortedEpisodes) + @foreach ($sortedEpisodes as $episode) + + + + + + + + + + @php $index++; @endphp + @endforeach + + + + @endforeach + +
TênSlugTypeLink
+ + + + Xóa
+
+
+ + +
+
+ @endforeach + @else +
+
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + +
TênSlugTypeLink
+ + + Xóa
+
+
+ @endif + +
+
+
+ + + + + + diff --git a/resources/views/core/sitemap/styles.blade.php b/resources/views/core/sitemap/styles.blade.php new file mode 100644 index 0000000..9b520b4 --- /dev/null +++ b/resources/views/core/sitemap/styles.blade.php @@ -0,0 +1,259 @@ +'; ?> + + + + + + + + Locations Sitemap + + + XML Sitemap + + + + + + + + +
+

KML File

+

+ This KML File is generated by + {{ $title }}. It is used to provide location information to Google. +

+

+ Learn more about + KML File. +

+
+
+

+ This KML file contains + Locations. + +

+

+ ← Sitemap Index +

+ + + + + + + + + + + + + + + + + + + + + + + +
NameAddressPhone numberLatitudeLongitude
+ + + + + + + + + + + + + + +
+
+
+ +
+

XML Sitemap

+

+ This XML Sitemap is generated by + {{ $title }}. It is what search engines like Google use to crawl and re-crawl posts/pages/products/images/archives on your website. +

+

+ Learn more about + XML Sitemaps. +

+
+
+ +

+ This XML Sitemap Index file contains + + + sitemaps. +

+ + + + + + + + + + + + + + + + + + +
SitemapLast Modified
+ + + + + +
+
+ +

+ This XML Sitemap contains + + + URLs. +

+

+ ← Sitemap Index +

+ + + + + + + + + + + + + + + + + + + +
URLImagesLast Mod.
+ + + + + + + + + + +
+
+
+
+
+ + +
+
diff --git a/resources/views/themes/layout.blade.php b/resources/views/themes/layout.blade.php new file mode 100644 index 0000000..bf09d57 --- /dev/null +++ b/resources/views/themes/layout.blade.php @@ -0,0 +1,25 @@ + + + + + {!! setting('site_meta_head_tags', '') !!} + + + + + {!! SEO::generate() !!} + @stack('header') + {!! get_theme_option('additional_css') !!} + {!! get_theme_option('additional_header_js') !!} + + + + @yield('body') + {!! get_theme_option('additional_body_js') !!} + + @yield('footer') + @stack('scripts') + {!! get_theme_option('additional_footer_js') !!} + + + diff --git a/routes/admin.php b/routes/admin.php new file mode 100644 index 0000000..2429423 --- /dev/null +++ b/routes/admin.php @@ -0,0 +1,57 @@ + config('backpack.base.route_prefix', 'admin'), + 'middleware' => array_merge( + (array) config('backpack.base.web_middleware', 'web'), + (array) config('backpack.base.middleware_key', 'admin') + ), + 'namespace' => 'Vsmov\Core\Controllers\Admin', +], function () { + if (config('backpack.base.setup_dashboard_routes')) { + Route::get('dashboard', 'AdminController@dashboard')->name('backpack.dashboard'); + Route::get('/', 'AdminController@redirect')->name('backpack'); + } + + Route::crud('catalog', 'CatalogCrudController'); + Route::crud('category', 'CategoryCrudController'); + Route::crud('region', 'RegionCrudController'); + Route::crud('movie', 'MovieCrudController'); + Route::crud('actor', 'ActorCrudController'); + Route::crud('director', 'DirectorCrudController'); + Route::crud('studio', 'StudioCrudController'); + Route::crud('tag', 'TagCrudController'); + Route::crud('menu', 'MenuCrudController'); + Route::crud('episode', 'EpisodeCrudController'); + Route::crud('theme', 'ThemeManagementController'); + Route::crud('sitemap', 'SiteMapController'); + Route::get('quick-action/delete-cache', 'QuickActionController@delete_cache'); +}); + +Route::group([ + 'prefix' => config('backpack.base.route_prefix', 'admin'), + 'middleware' => array_merge( + [ + \Vsmov\Core\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class + ], + (array) config('backpack.base.middleware_key', 'admin') + ), +], function () { + Route::prefix('/ckfinder')->group(function () { + Route::any('/connector', [CKFinderController::class, 'requestAction'])->name('ckfinder_connector'); + Route::any('/browser', [CKFinderController::class, 'browserAction'])->name('ckfinder_browser'); + }); +}); diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000..2199c36 Binary files /dev/null and b/src/.DS_Store differ diff --git a/src/Console/ChangeDomainEpisodeCommand.php b/src/Console/ChangeDomainEpisodeCommand.php new file mode 100644 index 0000000..515b75a --- /dev/null +++ b/src/Console/ChangeDomainEpisodeCommand.php @@ -0,0 +1,65 @@ + ['vie.opstream1.com', 'vie.haiphim.com'], + 'vip.opstream15.com' => ['hd.1080phim.com', 'hd1080.opstream2.com'], + 'vip.opstream14.com' => ['kd.hd-bophim.com', 'kd.opstream3.com'], + 'vip.opstream11.com' => ['1080.hdphimonline.com', '1080.opstream4.com'], + 'vip.opstream16.com' => ['hd.hdbophim.com', 'hdbo.opstream5.com'], + 'vip.opstream12.com' => ['aa.nguonphimmoi.com', 'aa.opstream6.com'], + 'vip.opstream13.com' => ['vie2.opstream7.com'], + 'vip.opstream17.com' => ['vip.opstream8.com'], + ); + foreach ($domains as $newDomain => $arrOldDomain) { + foreach ($arrOldDomain as $oldDomain) { + $this->info("Replace: $oldDomain => $newDomain"); + Episode::where('link', 'LIKE', '%' . $oldDomain . '%')->update(['link' => DB::raw("REPLACE(link, '$oldDomain', '$newDomain')")]); + } + } + + $this->info("Replace Done!"); + return 0; + } +} diff --git a/src/Console/CreateUser.php b/src/Console/CreateUser.php new file mode 100644 index 0000000..6c07b82 --- /dev/null +++ b/src/Console/CreateUser.php @@ -0,0 +1,74 @@ +info('Creating a new user'); + + if (!$name = $this->option('name')) { + $name = $this->ask('Name'); + } + + if (!$email = $this->option('email')) { + $email = $this->ask('Email'); + } + + if (!$password = $this->option('password')) { + $password = $this->secret('Password'); + } + + if (!$this->confirm('Is administrator? [y|N]', $isAdmin = false)) { + $isAdmin = false; + } else { + $isAdmin = true; + } + + if ($this->option('encrypt')) { + $password = bcrypt($password); + } + + $auth = config('backpack.base.user_model_fqn', 'App\User'); + $user = new $auth(); + $user->name = $name; + $user->email = $email; + $user->password = $password; + + if ($user->save()) { + $this->info('Successfully created new user'); + if ($isAdmin) { + $user->roles()->attach(Role::firstOrCreate(['name' => 'Admin', 'guard_name' => 'backpack'])); + } + } else { + $this->error('Something went wrong trying to save your user'); + } + } +} diff --git a/src/Console/GenerateMenuCommand.php b/src/Console/GenerateMenuCommand.php new file mode 100644 index 0000000..0124ad0 --- /dev/null +++ b/src/Console/GenerateMenuCommand.php @@ -0,0 +1,51 @@ +call('db:seed', [ + 'class' => MenusTableSeeder::class, + ]); + $this->info('Menu is generated.'); + + return 0; + } +} diff --git a/src/Console/InstallCommand.php b/src/Console/InstallCommand.php new file mode 100644 index 0000000..5cb56bf --- /dev/null +++ b/src/Console/InstallCommand.php @@ -0,0 +1,159 @@ +progressBar = $this->output->createProgressBar(18); + $this->progressBar->minSecondsBetweenRedraws(0); + $this->progressBar->maxSecondsBetweenRedraws(120); + $this->progressBar->setRedrawFrequency(1); + + $this->progressBar->start(); + + $this->call('vendor:publish', [ + '--provider' => 'Backpack\CRUD\BackpackServiceProvider', + '--tag' => 'config', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--provider' => 'Backpack\CRUD\BackpackServiceProvider', + '--tag' => 'config', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--provider' => 'Backpack\CRUD\BackpackServiceProvider', + '--tag' => 'public', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--provider' => 'Backpack\CRUD\BackpackServiceProvider', + '--tag' => 'gravatar', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + + $this->call('migrate', $this->option('no-interaction') ? ['--no-interaction' => true] : []); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('backpack:publish-middleware'); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--tag' => 'cms_menu_content', + '--force' => true + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--tag' => 'players', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->installCKfinder(); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('db:seed', [ + 'class' => SettingsTableSeeder::class, + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('db:seed', [ + 'class' => CatalogsTableSeeder::class, + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('db:seed', [ + 'class' => MenusTableSeeder::class, + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('db:seed', [ + 'class' => PermissionsSeeder::class, + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->progressBar->finish(); + $this->newLine(1); + $this->info('VsMov installation finished.'); + + return 0; + } + + protected function installCKfinder() + { + $this->call('ckfinder:download'); + $this->call('vendor:publish', [ + '--tag' => 'ckfinder-assets', + ]); + $this->progressBar->advance(); + $this->newLine(1); + + $this->call('vendor:publish', [ + '--tag' => 'ckfinder-config', + ]); + + $this->call('storage:link'); + } +} diff --git a/src/Contracts/HasUrlInterface.php b/src/Contracts/HasUrlInterface.php new file mode 100644 index 0000000..e182f57 --- /dev/null +++ b/src/Contracts/HasUrlInterface.php @@ -0,0 +1,8 @@ +authorize('browse', Actor::class); + + CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']); + CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Actor::class); + + CRUD::setValidation(ActorRequest::class); + + CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); + CRUD::addField([ + 'name' => 'gender', + 'label' => "Giới tính", + 'type' => 'select_from_array', + 'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'], + 'allows_null' => false, + 'default' => 'one', + ],); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->model); + } +} diff --git a/src/Controllers/Admin/AdminController.php b/src/Controllers/Admin/AdminController.php new file mode 100644 index 0000000..7a9f4a9 --- /dev/null +++ b/src/Controllers/Admin/AdminController.php @@ -0,0 +1,56 @@ +middleware(backpack_middleware()); + } + + /** + * Show the admin dashboard. + * + * @return \Illuminate\Http\Response + */ + public function dashboard() + { + $this->data['title'] = trans('backpack::base.dashboard'); // set the page title + $this->data['breadcrumbs'] = [ + trans('backpack::crud.admin') => backpack_url('dashboard'), + trans('backpack::base.dashboard') => false, + ]; + $this->data['count_movies'] = Movie::count(); + $this->data['count_episodes'] = Episode::count(); + $this->data['count_episodes_error'] = Episode::where('has_report', true)->count(); + $this->data['count_themes'] = Theme::count(); + $this->data['count_users'] = User::count(); + $this->data['top_view_day'] = Movie::orderBy('view_day', 'desc')->limit(15)->get(); + $this->data['top_view_week'] = Movie::orderBy('view_week', 'desc')->limit(15)->get(); + $this->data['top_view_month'] = Movie::orderBy('view_month', 'desc')->limit(15)->get(); + return view(backpack_view('dashboard'), $this->data); + } + + /** + * Redirect to the dashboard. + * + * @return \Illuminate\Routing\Redirector|\Illuminate\Http\RedirectResponse + */ + public function redirect() + { + // The '/admin' route is not to be used as a page, because it breaks the menu's active state. + return redirect(backpack_url('dashboard')); + } +} diff --git a/src/Controllers/Admin/CatalogCrudController.php b/src/Controllers/Admin/CatalogCrudController.php new file mode 100644 index 0000000..011fd95 --- /dev/null +++ b/src/Controllers/Admin/CatalogCrudController.php @@ -0,0 +1,94 @@ +authorize('browse', Catalog::class); + + CRUD::addButtonFromModelFunction('line', 'open_view', 'openView', 'beginning'); + + CRUD::column('name')->label('Tên')->type('text'); + CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::column('paginate')->label('Item per page')->type('number'); + CRUD::column('value')->label('Value')->type('text'); + CRUD::column('seo_title')->label('SEO Title')->type('text'); + CRUD::column('seo_des')->label('SEO Description')->type('text'); + CRUD::column('seo_key')->label('SEO Keyword')->type('text'); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Catalog::class); + + CRUD::setValidation(CatalogRequest::class); + + CRUD::field('name')->label('Tên')->type('text'); + CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::field('paginate')->label('Paginate')->hint('Item per page')->type('number'); + CRUD::field('value')->label('Value')->hint('relation_tables,relation_field,relation_value|find_by_field_1,find_by_fiel_2,...,find_by_field_n|value_1,value_2,...,value_n|sort_by_field|sort_algo')->type('text'); + CRUD::field('seo_title')->label('SEO Title')->type('text'); + CRUD::field('seo_des')->label('SEO Description')->type('textarea'); + CRUD::field('seo_key')->label('SEO Keyword')->type('text'); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/CategoryCrudController.php b/src/Controllers/Admin/CategoryCrudController.php new file mode 100644 index 0000000..efbd415 --- /dev/null +++ b/src/Controllers/Admin/CategoryCrudController.php @@ -0,0 +1,89 @@ +authorize('browse', Category::class); + + CRUD::column('name')->label('Tên')->type('text'); + CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::column('seo_title')->label('SEO Title')->type('text'); + CRUD::column('seo_des')->label('SEO Description')->type('text'); + CRUD::column('seo_key')->label('SEO Keyword')->type('text'); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Category::class); + + CRUD::setValidation(CategoryRequest::class); + + CRUD::field('name')->label('Tên')->type('text'); + CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::field('seo_title')->label('SEO Title')->type('text'); + CRUD::field('seo_des')->label('SEO Description')->type('textarea'); + CRUD::field('seo_key')->label('SEO Keyword')->type('text'); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/DirectorCrudController.php b/src/Controllers/Admin/DirectorCrudController.php new file mode 100644 index 0000000..5282f4b --- /dev/null +++ b/src/Controllers/Admin/DirectorCrudController.php @@ -0,0 +1,107 @@ +authorize('browse', Director::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); + */ + + + CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addColumn(['name' => 'gender', 'label' => 'Giới tính', 'type' => 'text']); + CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Director::class); + + CRUD::setValidation(DirectorRequest::class); + + /** + * Fields can be defined using the fluent syntax or array syntax: + * - CRUD::field('price')->type('number'); + * - CRUD::addField(['name' => 'price', 'type' => 'number'])); + */ + + CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); + CRUD::addField([ + 'name' => 'gender', + 'label' => "Giới tính", + 'type' => 'select_from_array', + 'options' => ['male' => 'Nam', 'female' => 'Nữ', 'other' => 'Khác'], + 'allows_null' => false, + 'default' => 'one', + ],); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/EpisodeCrudController.php b/src/Controllers/Admin/EpisodeCrudController.php new file mode 100644 index 0000000..eb69e2b --- /dev/null +++ b/src/Controllers/Admin/EpisodeCrudController.php @@ -0,0 +1,120 @@ +crud->addButtonFromModelFunction('line', 'open_episode', 'openEpisode', 'beginning'); + $this->crud->denyAccess('create'); + $this->crud->denyAccess('delete'); + } + + /** + * Define what happens when the List operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-list-entries + * @return void + */ + protected function setupListOperation() + { + $this->authorize('browse', Episode::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number','tab'=>'Thông tin phim']); + */ + $this->crud->enableExportButtons(); + $this->crud->addClause('where', 'has_report', true); + + CRUD::addColumn([ + 'name' => 'movie', 'label' => 'Phim', 'type' => 'relationship', + 'searchLogic' => function ($query, $column, $searchTerm) { + $query->orWhereHas('movie', function ($movie) use ($searchTerm) { + $movie->where('name', 'like', '%' . $searchTerm . '%') + ->orWhere('origin_name', 'like', '%' . $searchTerm . '%'); + }); + } + ]); + CRUD::addColumn(['name' => 'name', 'label' => 'Tập', 'type' => 'text']); + CRUD::addColumn(['name' => 'type', 'label' => 'Type', 'type' => 'text']); + CRUD::addColumn(['name' => 'link', 'label' => 'Link', 'type' => 'textarea']); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + abort(404); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + CRUD::addField(['name' => 'type', 'label' => 'Type', 'type' => 'select_from_array', 'options' => config('vsmov.episodes.types')]); + CRUD::addField(['name' => 'link', 'label' => 'Nguồn phát', 'type' => 'url']); + CRUD::addField(['name' => 'has_report', 'label' => 'Đánh dấu đang lỗi', 'type' => 'checkbox']); + CRUD::addField(['name' => 'report_message', 'label' => 'Report message', 'type' => 'textarea']); + } + + public function bulkDelete() + { + $this->crud->hasAccessOrFail('bulkDelete'); + $entries = request()->input('entries', []); + $deletedEntries = []; + + foreach ($entries as $key => $id) { + if ($entry = $this->crud->model->find($id)) { + $deletedEntries[] = $entry->update(['has_report' => 0, 'report_message' => '']); + } + } + + return $deletedEntries; + } +} diff --git a/src/Controllers/Admin/MenuCrudController.php b/src/Controllers/Admin/MenuCrudController.php new file mode 100644 index 0000000..7a6b907 --- /dev/null +++ b/src/Controllers/Admin/MenuCrudController.php @@ -0,0 +1,126 @@ +crud->setModel(Menu::class); + $this->crud->setRoute(config('backpack.base.route_prefix') . '/menu'); + $this->crud->setEntityNameStrings('menu item', 'menu items'); + $this->crud->enableReorder('name', 2); + } + + /** + * Define what happens when the List operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-list-entries + * @return void + */ + protected function setupListOperation() + { + $this->authorize('browse', Menu::class); + + $this->crud->addColumn([ + 'name' => 'name', + 'label' => 'Label', + ]); + $this->crud->addColumn([ + 'label' => 'Parent', + 'type' => 'select', + 'name' => 'parent_id', + 'entity' => 'parent', + 'attribute' => 'name', + 'model' => Menu::class, + ]); + $this->crud->addColumn([ + 'name' => 'link', + 'label' => 'Link', + 'type' => 'url', + ]); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Menu::class); + + $this->crud->addField([ + 'name' => 'name', + 'label' => 'Label', + ]); + $this->crud->addField([ + 'label' => 'Parent', + 'type' => 'select', + 'name' => 'parent_id', + 'entity' => 'parent', + 'attribute' => 'name', + Menu::class + ]); + + $this->crud->addField([ + 'name' => ['type', 'link', 'internal_link'], + 'label' => 'Type', + 'type' => 'page_or_link', + ]); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } + + public function bulkDelete() + { + $this->crud->hasAccessOrFail('bulkDelete'); + $entries = request()->input('entries', []); + $deletedEntries = []; + foreach ($entries as $key => $id) { + if ($entry = $this->crud->model->find($id)) { + $deletedEntries[] = $entry->delete(); + } + } + + return $deletedEntries; + } +} diff --git a/src/Controllers/Admin/MovieCrudController.php b/src/Controllers/Admin/MovieCrudController.php new file mode 100644 index 0000000..cb0fa03 --- /dev/null +++ b/src/Controllers/Admin/MovieCrudController.php @@ -0,0 +1,409 @@ +authorize('browse', Movie::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number','tab'=>'Thông tin phim']); + */ + + $this->crud->addFilter([ + 'name' => 'status', + 'type' => 'select2', + 'label' => 'Tình trạng' + ], function () { + return [ + 'trailer' => 'Sắp chiếu', + 'ongoing' => 'Đang chiếu', + 'completed' => 'Hoàn thành' + ]; + }, function ($val) { + $this->crud->addClause('where', 'status', $val); + }); + + $this->crud->addFilter([ + 'name' => 'type', + 'type' => 'select2', + 'label' => 'Định dạng' + ], function () { + return [ + 'single' => 'Phim lẻ', + 'series' => 'Phim bộ' + ]; + }, function ($val) { + $this->crud->addClause('where', 'type', $val); + }); + + $this->crud->addFilter([ + 'name' => 'category_id', + 'type' => 'select2', + 'label' => 'Thể loại' + ], function () { + return Category::all()->pluck('name', 'id')->toArray(); + }, function ($value) { // if the filter is active + $this->crud->query = $this->crud->query->whereHas('categories', function ($query) use ($value) { + $query->where('id', $value); + }); + }); + + $this->crud->addFilter([ + 'name' => 'region_id', + 'type' => 'select2', + 'label' => 'Quốc gia' + ], function () { + return Region::all()->pluck('name', 'id')->toArray(); + }, function ($value) { // if the filter is active + $this->crud->query = $this->crud->query->whereHas('regions', function ($query) use ($value) { + $query->where('id', $value); + }); + }); + + $this->crud->addFilter([ + 'name' => 'other', + 'type' => 'select2', + 'label' => 'Thông tin' + ], function () { + return [ + 'thumb_url-' => 'Thiếu ảnh thumb', + 'poster_url-' => 'Thiếu ảnh poster', + 'trailer_url-' => 'Thiếu trailer', + 'language-vietsub' => 'Vietsub', + 'language-thuyết minh' => 'Thuyết minh', + 'language-lồng tiếng' => 'Lồng tiếng', + ]; + }, function ($values) { + $value = explode("-", $values); + $field = $value[0]; + $val = $value[1]; + if ($field === 'language') { + $this->crud->query->where($field, 'like', '%' . $val . '%'); + } else { + $this->crud->query->where($field, '')->orWhere($field, NULL)->orWhere($field, 'like', '%img.vsmov%')->orWhere($field, 'like', '%img.hiephanhthienha%'); + } + }); + + $this->crud->addFilter( + [ + 'type' => 'simple', + 'name' => 'is_recommended', + 'label' => 'Đề cử' + ], + false, + function () { + $this->crud->addClause('where', 'is_recommended', true); + } + ); + + $this->crud->addFilter( + [ + 'type' => 'simple', + 'name' => 'is_shown_in_theater', + 'label' => 'Chiếu rạp' + ], + false, + function () { + $this->crud->addClause('where', 'is_shown_in_theater', true); + } + ); + + CRUD::addButtonFromModelFunction('line', 'open_view', 'openView', 'beginning'); + + CRUD::addColumn([ + 'name' => 'name', + 'origin_name' => 'origin_name', + 'publish_year' => 'publish_year', + 'status' => 'status', + 'movie_type' => 'type', + 'episode_current' => 'episode_current', + 'label' => 'Thông tin', + 'type' => 'view', + 'view' => 'vsmov::movies.columns.column_movie_info', + 'searchLogic' => function ($query, $column, $searchTerm) { + $query->where('name', 'like', '%' . $searchTerm . '%')->orWhere('origin_name', 'like', '%' . $searchTerm . '%'); + // $query->whereRaw("MATCH(name, origin_name) AGAINST(? IN BOOLEAN MODE)", [$searchTerm]); + } + ]); + + CRUD::addColumn([ + 'name' => 'thumb_url', 'label' => 'Ảnh thumb', 'type' => 'image', + 'height' => '100px', + 'width' => '68px', + ]); + CRUD::addColumn(['name' => 'categories', 'label' => 'Thể loại', 'type' => 'relationship',]); + CRUD::addColumn(['name' => 'regions', 'label' => 'Khu vực', 'type' => 'relationship',]); + CRUD::addColumn(['name' => 'updated_at', 'label' => 'Cập nhật lúc', 'type' => 'datetime', 'format' => 'DD/MM/YYYY HH:mm:ss']); + // CRUD::addColumn(['name' => 'user_name', 'label' => 'Cập nhật bởi', 'type' => 'text',]); + CRUD::addColumn(['name' => 'view_total', 'label' => 'Lượt xem', 'type' => 'number',]); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Movie::class); + + CRUD::setValidation(MovieRequest::class); + + /** + * Fields can be defined using the fluent syntax or array syntax: + * - CRUD::field('price')->type('number'); + * - CRUD::addField(['name' => 'price', 'type' => 'number'])); + */ + + CRUD::addField(['name' => 'name', 'label' => 'Tên phim', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-6' + ], 'attributes' => ['placeholder' => 'Tên'], 'tab' => 'Thông tin phim']); + CRUD::addField(['name' => 'origin_name', 'label' => 'Tên gốc', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-6' + ], 'tab' => 'Thông tin phim']); + CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text', 'tab' => 'Thông tin phim']); + CRUD::addField([ + 'name' => 'thumb_url', 'label' => 'Ảnh Thumb', 'type' => 'ckfinder', 'preview' => ['width' => 'auto', 'height' => '340px'], 'tab' => 'Thông tin phim' + ]); + CRUD::addField(['name' => 'poster_url', 'label' => 'Ảnh Poster', 'type' => 'ckfinder', 'preview' => ['width' => 'auto', 'height' => '340px'], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'content', 'label' => 'Nội dung', 'type' => 'summernote', 'tab' => 'Thông tin phim']); + CRUD::addField(['name' => 'notify', 'label' => 'Thông báo / ghi chú', 'type' => 'text', 'attributes' => ['placeholder' => 'Tuần này hoãn chiếu'], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'showtimes', 'label' => 'Lịch chiếu phim', 'type' => 'text', 'attributes' => ['placeholder' => '21h tối hàng ngày'], 'tab' => 'Thông tin phim']); + CRUD::addField(['name' => 'trailer_url', 'label' => 'Trailer Youtube URL', 'type' => 'text', 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'episode_time', 'label' => 'Thời lượng tập phim', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'attributes' => ['placeholder' => '45 phút'], 'tab' => 'Thông tin phim']); + CRUD::addField(['name' => 'episode_current', 'label' => 'Tập phim hiện tại', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'attributes' => ['placeholder' => '5'], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'episode_total', 'label' => 'Tổng số tập phim', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'attributes' => ['placeholder' => '12'], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'language', 'label' => 'Ngôn ngữ', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'attributes' => ['placeholder' => 'Tiếng Việt'], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'quality', 'label' => 'Chất lượng', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'publish_year', 'label' => 'Năm xuất bản', 'type' => 'text', 'wrapperAttributes' => [ + 'class' => 'form-group col-md-4' + ], 'tab' => 'Thông tin phim']); + + CRUD::addField(['name' => 'type', 'label' => 'Định dạng', 'type' => 'radio', 'options' => ['single' => 'Phim lẻ', 'series' => 'Phim bộ'], 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'status', 'label' => 'Tình trạng', 'type' => 'radio', 'options' => ['trailer' => 'Sắp chiếu', 'ongoing' => 'Đang chiếu', 'completed' => 'Hoàn thành'], 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'categories', 'label' => 'Thể loại', 'type' => 'checklist', 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'regions', 'label' => 'Khu vực', 'type' => 'checklist', 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'directors', 'label' => 'Đạo diễn', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'actors', 'label' => 'Diễn viên', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'tags', 'label' => 'Tags', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']); + CRUD::addField(['name' => 'studios', 'label' => 'Studios', 'type' => 'select2_relationship_tags', 'tab' => 'Phân loại']); + + CRUD::addField([ + 'name' => 'episodes', + 'type' => 'view', + 'view' => 'vsmov::movies.inc.episode', + 'tab' => 'Danh sách tập phim' + ],); + + CRUD::addField(['name' => 'update_handler', 'label' => 'Trình cập nhật', 'type' => 'select_from_array', 'options' => collect(config('vsmov.updaters', []))->pluck('name', 'handler')->toArray(), 'tab' => 'Cập nhật']); + CRUD::addField(['name' => 'update_identity', 'label' => 'ID cập nhật', 'type' => 'text', 'tab' => 'Cập nhật']); + + CRUD::addField(['name' => 'is_shown_in_theater', 'label' => 'Phim chiếu rạp', 'type' => 'boolean', 'tab' => 'Khác']); + CRUD::addField(['name' => 'is_copyright', 'label' => 'Có bản quyền phim', 'type' => 'boolean', 'tab' => 'Khác']); + CRUD::addField(['name' => 'is_sensitive_content', 'label' => 'Cảnh báo nội dung người lớn', 'type' => 'boolean', 'tab' => 'Khác']); + CRUD::addField(['name' => 'is_recommended', 'label' => 'Đề cử', 'type' => 'boolean', 'tab' => 'Khác']); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + $this->setupCreateOperation(); + CRUD::addField(['name' => 'timestamps', 'label' => 'Cập nhật thời gian', 'type' => 'checkbox', 'tab' => 'Cập nhật']); + } + + public function store(Request $request) + { + $this->getTaxonamies($request); + + return $this->backpackStore(); + } + + public function update(Request $request) + { + $this->getTaxonamies($request); + + return $this->backpackUpdate(); + } + + protected function getTaxonamies(Request $request) + { + $actors = request('actors', []); + $directors = request('directors', []); + $tags = request('tags', []); + $studios = request('studios', []); + + $actor_ids = []; + foreach ($actors as $actor) { + $actor_ids[] = Actor::firstOrCreate([ + 'name_md5' => md5($actor) + ], [ + 'name' => $actor + ])->id; + } + + $director_ids = []; + foreach ($directors as $director) { + $director_ids[] = Director::firstOrCreate([ + 'name_md5' => md5($director) + ], [ + 'name' => $director + ])->id; + } + + $tag_ids = []; + foreach ($tags as $tag) { + $tag_ids[] = Tag::firstOrCreate([ + 'name_md5' => md5($tag) + ], [ + 'name' => $tag + ])->id; + } + + $studio_ids = []; + foreach ($studios as $studio) { + $studio_ids[] = Studio::firstOrCreate([ + 'name_md5' => md5($studio) + ], [ + 'name' => $studio + ])->id; + } + + $request['actors'] = $actor_ids; + $request['directors'] = $director_ids; + $request['tags'] = $tag_ids; + $request['studios'] = $studio_ids; + } + + // protected function setupDeleteOperation() + // { + // $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + // } + + public function deleteImage($movie) + { + // Delete images + if ($movie->thumb_url && !filter_var($movie->thumb_url, FILTER_VALIDATE_URL) && file_exists(public_path($movie->thumb_url))) { + unlink(public_path($movie->thumb_url)); + } + if ($movie->poster_url && !filter_var($movie->poster_url, FILTER_VALIDATE_URL) && file_exists(public_path($movie->poster_url))) { + unlink(public_path($movie->poster_url)); + } + return true; + } + + public function destroy($id) + { + $this->crud->hasAccessOrFail('delete'); + $movie = Movie::find($id); + + $this->deleteImage($movie); + + // get entry ID from Request (makes sure its the last ID for nested resources) + $id = $this->crud->getCurrentEntryId() ?? $id; + + $res = $this->crud->delete($id); + if ($res) { + } + return $res; + } + + public function bulkDelete() + { + $this->crud->hasAccessOrFail('bulkDelete'); + $entries = request()->input('entries', []); + $deletedEntries = []; + + foreach ($entries as $key => $id) { + if ($entry = $this->crud->model->find($id)) { + $this->deleteImage($entry); + $deletedEntries[] = $entry->delete(); + } + } + + return $deletedEntries; + } +} diff --git a/src/Controllers/Admin/PluginController.php b/src/Controllers/Admin/PluginController.php new file mode 100644 index 0000000..f301648 --- /dev/null +++ b/src/Controllers/Admin/PluginController.php @@ -0,0 +1,157 @@ +crud->denyAccess('update'); + } + + /** + * Define what happens when the List operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-list-entries + * @return void + */ + protected function setupListOperation() + { + if (!backpack_user()->hasPermissionTo('Browse plugin')) { + abort(403); + } + + CRUD::column('name')->label('Plugin')->type('text'); + CRUD::column('version')->label('Version')->type('text'); + $this->crud->addButtonFromModelFunction('line', 'editBtn', 'editBtn', 'beginning'); + $this->crud->addButtonFromModelFunction('line', 'openBtn', 'openBtn', 'beginning'); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $plugin = $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()); + + $fields = $plugin->options; + + CRUD::addField(['name' => 'fields', 'type' => 'hidden', 'value' => collect($fields)->implode('name', ',')]); + + foreach ($fields as $field) { + CRUD::addField($field); + } + } + + public function show($id) + { + /** @var Plugin */ + $plugin = Plugin::findOrFail($id); + + return $plugin->open(); + } + + /** + * Show the form for editing the specified resource. + * + * @return \Illuminate\Contracts\View\View + */ + public function edit($id) + { + if (!backpack_user()->hasPermissionTo('Update plugin')) { + abort(403); + } + $id = $this->crud->getCurrentEntryId() ?? $id; + + $this->data['entry'] = $this->crud->getEntryWithLocale($id); + $this->crud->setOperationSetting('fields', $this->getUpdateFields()); + + $this->data['crud'] = $this->crud; + $this->data['saveAction'] = $this->crud->getSaveAction(); + $this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.edit') . ' ' . $this->crud->entity_name; + $this->data['id'] = $id; + + // load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package + return view($this->crud->getEditView(), $this->data); + } + + /** + * Update the specified resource in the database. + * + * @return array|\Illuminate\Http\RedirectResponse + */ + public function update($plugin) + { + if (!backpack_user()->hasPermissionTo('Update plugin')) { + abort(403); + } + + // execute the FormRequest authorization and validation, if one is required + $request = $this->crud->validateRequest(); + + // register any Model Events defined on fields + $this->crud->registerFieldEvents(); + + // update the row in the db + $item = $this->crud->update( + $request->get($this->crud->model->getKeyName()), + [ + 'value' => request()->only(explode(',', request('fields'))) + ] + ); + $this->data['entry'] = $this->crud->entry = $item; + + // show a success message + Alert::success(trans('backpack::crud.update_success'))->flash(); + + return redirect(backpack_url('plugin')); + } + + /** + * Get all fields needed for the EDIT ENTRY form. + * + * @param int $id The id of the entry that is being edited. + * @return array The fields with attributes, fake attributes and values. + */ + public function getUpdateFields($id = false) + { + $fields = $this->crud->fields(); + $entry = ($id != false) ? $this->getEntry($id) : $this->crud->getCurrentEntry(); + $options = $entry->value ?? []; + + foreach ($options as $k => $v) { + $fields[$k]['value'] = $v; + } + + if (!array_key_exists('id', $fields)) { + $fields['id'] = [ + 'name' => $entry->getKeyName(), + 'value' => $entry->getKey(), + 'type' => 'hidden', + ]; + } + + return $fields; + } +} diff --git a/src/Controllers/Admin/QuickActionController.php b/src/Controllers/Admin/QuickActionController.php new file mode 100644 index 0000000..45ba573 --- /dev/null +++ b/src/Controllers/Admin/QuickActionController.php @@ -0,0 +1,23 @@ +flash(); + return back(); + } +} diff --git a/src/Controllers/Admin/RegionCrudController.php b/src/Controllers/Admin/RegionCrudController.php new file mode 100644 index 0000000..0fd5648 --- /dev/null +++ b/src/Controllers/Admin/RegionCrudController.php @@ -0,0 +1,98 @@ +authorize('browse', Region::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->label('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); + */ + CRUD::column('name')->label('Tên khu vực')->type('text'); + CRUD::column('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::column('seo_title')->label('SEO Title')->type('text'); + CRUD::column('seo_des')->label('SEO Description')->type('text'); + CRUD::column('seo_key')->label('SEO Keyword')->type('text'); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Region::class); + + CRUD::setValidation(RegionRequest::class); + + /** + * Fields can be defined using the fluent syntax or array syntax: + * - CRUD::field('price')->label('price')->type('number'); + * - CRUD::addField(['name' => 'price', 'type' => 'number'])); + */ + CRUD::field('name')->label('Tên khu vực')->type('text'); + CRUD::field('slug')->label('Đường dẫn tĩnh')->type('text'); + CRUD::field('seo_title')->label('SEO Title')->type('text'); + CRUD::field('seo_des')->label('SEO Description')->type('textarea'); + CRUD::field('seo_key')->label('SEO Keyword')->type('text'); + } + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/SiteMapController.php b/src/Controllers/Admin/SiteMapController.php new file mode 100644 index 0000000..826e8ce --- /dev/null +++ b/src/Controllers/Admin/SiteMapController.php @@ -0,0 +1,163 @@ + 'sitemap', 'type' => 'custom_html', 'value' => 'Sitemap sẽ được lưu tại đường dẫn: ' . url('/sitemap.xml') . '']); + $this->crud->addSaveAction([ + 'name' => 'save_and_new', + 'redirect' => function ($crud, $request, $itemId) { + return $crud->route; + }, + 'button_text' => 'Tạo sitemap', + ]); + + $this->crud->setOperationSetting('showSaveActionChange', false); + } + + public function render_styles() + { + $xml = view('vsmov::sitemap/styles', [ + 'title' => Setting::get('site_homepage_title'), + 'domain' => LARURL::to('/') + ])->render(); + + file_put_contents(public_path('main-sitemap.xsl'), $xml); + return; + } + + public function add_styles($file_name) + { + $path = public_path($file_name); + if(file_exists($path)) { + $content = file_get_contents($path); + $content = str_replace('?'.'>', '?'.'>'.'<'.'?'.'xml-stylesheet type="text/xsl" href="'. LARURL::to('/') .'/main-sitemap.xsl"?'.'>', $content); + file_put_contents($path, $content); + } + } + + public function store(Request $request) + { + $this->render_styles(); + if (!File::isDirectory('sitemap')) File::makeDirectory('sitemap', 0777, true, true); + + $sitemap_index = SitemapIndex::create(); + + $sitemap_page = Sitemap::create(); + $sitemap_page->add(Url::create('/') + ->setLastModificationDate(now()) + ->setChangeFrequency(Url::CHANGE_FREQUENCY_HOURLY) + ->setPriority(1)); + Catalog::chunkById(100, function ($catalogs) use ($sitemap_page) { + foreach ($catalogs as $catalog) { + $sitemap_page->add( + Url::create($catalog->getUrl()) + ->setLastModificationDate(now()) + ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) + ->setPriority(0.9) + ); + } + }); + $sitemap_page->writeToFile(public_path('sitemap/page-sitemap.xml')); + $this->add_styles('sitemap/page-sitemap.xml'); + $sitemap_index->add('sitemap/page-sitemap.xml'); + + $sitemap_categories = Sitemap::create(); + Category::chunkById(100, function ($categoires) use ($sitemap_categories) { + foreach ($categoires as $category) { + $sitemap_categories->add( + Url::create($category->getUrl()) + ->setLastModificationDate(now()) + ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) + ->setPriority(0.8) + ); + } + }); + $sitemap_categories->writeToFile(public_path('sitemap/categories-sitemap.xml')); + $this->add_styles('sitemap/categories-sitemap.xml'); + $sitemap_index->add('sitemap/categories-sitemap.xml'); + + $sitemap_regions = Sitemap::create(); + Region::chunkById(100, function ($regions) use ($sitemap_regions) { + foreach ($regions as $region) { + $sitemap_regions->add( + Url::create($region->getUrl()) + ->setLastModificationDate(now()) + ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) + ->setPriority(0.8) + ); + } + }); + $sitemap_regions->writeToFile(public_path('sitemap/regions-sitemap.xml')); + $this->add_styles('sitemap/regions-sitemap.xml'); + $sitemap_index->add('sitemap/regions-sitemap.xml'); + + $chunk = 0; + Movie::chunkById(200, function ($movies) use ($sitemap_index, &$chunk) { + $chunk++; + $sitemap_movies = null; + $sitemap_movies = Sitemap::create(); + foreach ($movies as $movie) { + $sitemap_movies->add( + Url::create($movie->getUrl()) + ->setLastModificationDate($movie->updated_at) + ->setChangeFrequency(Url::CHANGE_FREQUENCY_DAILY) + ->setPriority(0.7) + ); + } + $sitemap_movies->writeToFile(public_path("sitemap/movies-sitemap{$chunk}.xml")); + $this->add_styles("sitemap/movies-sitemap{$chunk}.xml"); + $sitemap_index->add("sitemap/movies-sitemap{$chunk}.xml"); + }); + + $sitemap_index->writeToFile(public_path('sitemap.xml')); + $this->add_styles("sitemap.xml"); + + Alert::success("Đã tạo thành công sitemap tại thư mục public")->flash(); + + return back(); + } +} diff --git a/src/Controllers/Admin/StudioCrudController.php b/src/Controllers/Admin/StudioCrudController.php new file mode 100644 index 0000000..7d1280c --- /dev/null +++ b/src/Controllers/Admin/StudioCrudController.php @@ -0,0 +1,97 @@ +authorize('browse', Studio::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); + */ + + CRUD::addColumn(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addColumn(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addColumn(['name' => 'image', 'label' => 'Ảnh', 'type' => 'image']); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Studio::class); + + CRUD::setValidation(StudioRequest::class); + + /** + * Fields can be defined using the fluent syntax or array syntax: + * - CRUD::field('price')->type('number'); + * - CRUD::addField(['name' => 'price', 'type' => 'number'])); + */ + + CRUD::addField(['name' => 'name', 'label' => 'Tên', 'type' => 'text']); + CRUD::addField(['name' => 'slug', 'label' => 'Đường dẫn tĩnh', 'type' => 'text']); + CRUD::addField(['name' => 'image', 'label' => 'Ảnh', 'type' => 'upload']); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/TagCrudController.php b/src/Controllers/Admin/TagCrudController.php new file mode 100644 index 0000000..d780778 --- /dev/null +++ b/src/Controllers/Admin/TagCrudController.php @@ -0,0 +1,95 @@ +authorize('browse', Tag::class); + + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); + */ + + CRUD::addColumn(['name' => 'name', 'type' => 'text']); + CRUD::addColumn(['name' => 'slug', 'type' => 'text']); + } + + /** + * Define what happens when the Create operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-create + * @return void + */ + protected function setupCreateOperation() + { + $this->authorize('create', Tag::class); + + CRUD::setValidation(TagRequest::class); + + /** + * Fields can be defined using the fluent syntax or array syntax: + * - CRUD::field('price')->type('number'); + * - CRUD::addField(['name' => 'price', 'type' => 'number'])); + */ + + CRUD::addField(['name' => 'name', 'type' => 'text']); + CRUD::addField(['name' => 'slug', 'type' => 'text']); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $this->authorize('update', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + + + $this->setupCreateOperation(); + } + + protected function setupDeleteOperation() + { + $this->authorize('delete', $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId())); + } +} diff --git a/src/Controllers/Admin/ThemeManagementController.php b/src/Controllers/Admin/ThemeManagementController.php new file mode 100644 index 0000000..cc789bf --- /dev/null +++ b/src/Controllers/Admin/ThemeManagementController.php @@ -0,0 +1,252 @@ +crud->denyAccess('update'); + } + + /** + * Define which routes are needed for this operation. + * + * @param string $name Name of the current entity (singular). Used as first URL segment. + * @param string $routeName Prefix of the route name. + * @param string $controller Name of the current CrudController. + */ + protected function setupManagementRoutes($segment, $routeName, $controller) + { + Route::post($segment . '/{id}/active', [ + 'as' => $routeName . '.active', + 'uses' => $controller . '@active', + 'operation' => 'update', + ]); + + Route::post($segment . '/{id}/reset', [ + 'as' => $routeName . '.reset', + 'uses' => $controller . '@reset', + 'operation' => 'update', + ]); + + Route::post($segment . '/{id}/delete', [ + 'as' => $routeName . '.delete', + 'uses' => $controller . '@delete', + 'operation' => 'update', + ]); + } + + /** + * Define what happens when the List operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-list-entries + * @return void + */ + protected function setupListOperation() + { + /** + * Columns can be defined using the fluent syntax or array syntax: + * - CRUD::column('price')->type('number'); + * - CRUD::addColumn(['name' => 'price', 'type' => 'number']); + */ + + foreach (config('themes', []) as $key => $theme) { + Theme::updateOrCreate([ + 'name' => $key, + ], [ + 'display_name' => $theme['display_name'] ?? $theme['name'], + 'preview_image' => $theme['preview_image'] ?: '', + 'author' => $theme['author'] ?: '', + 'package_name' => $theme['package_name'], + ]); + } + + CRUD::addColumn(['name' => 'display_name', 'type' => 'text']); + CRUD::addColumn(['name' => 'preview_image', 'type' => 'image']); + CRUD::addColumn(['name' => 'version', 'type' => 'text']); + $this->crud->addButtonFromModelFunction('line', 'editBtn', 'editBtn', 'beginning'); + $this->crud->addButtonFromModelFunction('line', 'resetBtn', 'resetBtn', 'beginning'); + $this->crud->addButtonFromModelFunction('line', 'activeBtn', 'activeBtn', 'beginning'); + $this->crud->addButtonFromModelFunction('line', 'deleteBtn', 'deleteBtn', ''); + } + + /** + * Define what happens when the Update operation is loaded. + * + * @see https://backpackforlaravel.com/docs/crud-operation-update + * @return void + */ + protected function setupUpdateOperation() + { + $theme = $this->crud->getEntryWithLocale($this->crud->getCurrentEntryId()); + + $fields = $theme->options; + + CRUD::addField(['name' => 'fields', 'type' => 'hidden', 'value' => collect($fields)->implode('name', ',')]); + + foreach ($fields as $field) { + CRUD::addField($field); + } + } + + public function delete(Request $request, $id) + { + if (!backpack_user()->hasPermissionTo('Customize theme')) { + abort(403); + } + $theme = Theme::fromCache()->find($id); + if (is_null($theme)) { + Alert::warning("Không tìm thấy dữ liệu giao diện")->flash(); + return redirect(backpack_url('theme')); + } + // delete row from db + $theme->delete(); + + Alert::success("Xóa giao diện thành công!")->flash(); + return redirect(backpack_url('theme')); + } + + /** + * Show the form for editing the specified resource. + * + * @param int $id + * @return \Illuminate\Contracts\View\View + */ + public function edit($id) + { + if (!backpack_user()->hasPermissionTo('Customize theme')) { + abort(403); + } + + $id = $this->crud->getCurrentEntryId() ?? $id; + + $this->data['entry'] = $this->crud->getEntryWithLocale($id); + $this->crud->setOperationSetting('fields', $this->getUpdateFields()); + + $this->data['crud'] = $this->crud; + $this->data['saveAction'] = $this->crud->getSaveAction(); + $this->data['title'] = $this->crud->getTitle() ?? trans('backpack::crud.edit') . ' ' . $this->crud->entity_name; + $this->data['id'] = $id; + + // load the view from /resources/views/vendor/backpack/crud/ if it exists, otherwise load the one in the package + return view($this->crud->getEditView(), $this->data); + } + + /** + * Update the specified resource in the database. + * + * @return array|\Illuminate\Http\RedirectResponse + */ + public function update() + { + if (!backpack_user()->hasPermissionTo('Customize theme')) { + abort(403); + } + + // execute the FormRequest authorization and validation, if one is required + $request = $this->crud->validateRequest(); + + // register any Model Events defined on fields + $this->crud->registerFieldEvents(); + + // update the row in the db + $item = $this->crud->update( + $request->get($this->crud->model->getKeyName()), + [ + 'value' => request()->only(explode(',', request('fields'))) + ] + ); + + $this->data['entry'] = $this->crud->entry = $item; + + Alert::success(trans('backpack::crud.update_success'))->flash(); + + return redirect(backpack_url('theme')); + } + + /** + * Get all fields needed for the EDIT ENTRY form. + * + * @param int $id The id of the entry that is being edited. + * @return array The fields with attributes, fake attributes and values. + */ + public function getUpdateFields($id = false) + { + $fields = $this->crud->fields(); + $entry = ($id != false) ? $this->getEntry($id) : $this->crud->getCurrentEntry(); + $options = $entry->value ?? []; + + foreach ($options as $k => $v) { + $fields[$k]['value'] = $v; + } + + if (!array_key_exists('id', $fields)) { + $fields['id'] = [ + 'name' => $entry->getKeyName(), + 'value' => $entry->getKey(), + 'type' => 'hidden', + ]; + } + + return $fields; + } + + public function reset(Request $request, $id) + { + $theme = Theme::fromCache()->find($id); + + if (is_null($theme)) { + Alert::warning("Không tìm thấy dữ liệu giao diện")->flash(); + return redirect(backpack_url('theme')); + } + + $fields = collect($theme->options); + + $theme->update([ + 'value' => $fields->pluck('value', 'name')->toArray() + ]); + + Alert::success(trans('backpack::crud.update_success'))->flash(); + + return redirect(backpack_url('theme')); + } + + public function active($id) + { + $theme = Theme::fromCache()->find($id); + + if (is_null($theme)) { + Alert::warning("Không tìm thấy dữ liệu giao diện")->flash(); + return redirect(backpack_url('theme')); + } + + $res = $theme->active(); + + if ($res) { + Alert::success(trans('backpack::crud.update_success'))->flash(); + } else { + Alert::error(trans('backpack::crud.update_failed'))->flash(); + } + + return redirect(backpack_url('theme')); + } +} diff --git a/src/Controllers/Controller.php b/src/Controllers/Controller.php new file mode 100644 index 0000000..ef1d12d --- /dev/null +++ b/src/Controllers/Controller.php @@ -0,0 +1,13 @@ +options, 'value', 'name') ?? [], + is_array($theme->value) ? $theme->value : [] + )); + + return $props[$key] ?? $fallback; + } +} diff --git a/src/Middleware/CKFinderAuth.php b/src/Middleware/CKFinderAuth.php new file mode 100644 index 0000000..e26f857 --- /dev/null +++ b/src/Middleware/CKFinderAuth.php @@ -0,0 +1,26 @@ + function () { + return true; + }]); + + return $next($request); + } +} diff --git a/src/Middleware/EncryptCookies.php b/src/Middleware/EncryptCookies.php new file mode 100644 index 0000000..a4d81aa --- /dev/null +++ b/src/Middleware/EncryptCookies.php @@ -0,0 +1,17 @@ + + */ + protected $except = [ + 'ckCsrfToken' + ]; +} diff --git a/src/Middleware/VerifyCsrfToken.php b/src/Middleware/VerifyCsrfToken.php new file mode 100644 index 0000000..278b9e4 --- /dev/null +++ b/src/Middleware/VerifyCsrfToken.php @@ -0,0 +1,17 @@ + + */ + protected $except = [ + 'ckfinder/*', + ]; +} diff --git a/src/Models/Actor.php b/src/Models/Actor.php new file mode 100644 index 0000000..8131c2c --- /dev/null +++ b/src/Models/Actor.php @@ -0,0 +1,191 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('actors.movies.index', $params); + } + + protected function titlePattern(): string + { + return Setting::get('site_actor_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_actor_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_actor_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->getTitle(); + $seo_des = Str::limit($this->getDescription(), 150, '...'); + $seo_key = $this->getKeywords(); + $movie_thumb_url = ''; + $movie_poster_url = ''; + $updated_at = ''; + if(count($this->movies)) { + $movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url; + $movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url; + $updated_at = $this->movies->last()->updated_at; + } + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $updated_at) + ->addProperty('url', $getUrl) + ->setDescription($seo_des) + ->addImages([$movie_thumb_url, $movie_poster_url]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->addValue('dateCreated', $updated_at) + ->addValue('dateModified', $updated_at) + ->addValue('datePublished', $updated_at) + ->setDescription($seo_des) + ->setImages([$movie_thumb_url, $movie_poster_url]) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Catalog.php b/src/Models/Catalog.php new file mode 100644 index 0000000..be4d19d --- /dev/null +++ b/src/Models/Catalog.php @@ -0,0 +1,153 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('types.movies.index', $params); + } + + public function generateSeoTags() + { + $seo_title = $this->seo_title; + $seo_des = $this->seo_des; + $seo_key = $this->seo_key; + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('url', $getUrl) + ->setDescription($seo_des); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->setDescription($seo_des) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + public function openView($crud = false) + { + return ' View'; + } + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Category.php b/src/Models/Category.php new file mode 100644 index 0000000..584435e --- /dev/null +++ b/src/Models/Category.php @@ -0,0 +1,192 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('categories.movies.index', $params, $withDomain); + } + + protected function titlePattern(): string + { + return Setting::get('site_category_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_category_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_category_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->seo_title ?: $this->getTitle(); + $seo_des = Str::limit($this->seo_des ?: $this->getDescription(), 150, '...'); + $seo_key = $this->seo_key ?: $this->getKeywords(); + $movie_thumb_url = ''; + $movie_poster_url = ''; + $updated_at = ''; + if(count($this->movies)) { + $movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url; + $movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url; + $updated_at = $this->movies->last()->updated_at; + } + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $updated_at) + ->addProperty('url', $getUrl) + ->setDescription($seo_des) + ->addImages([$movie_thumb_url,$movie_poster_url]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->addValue('dateCreated', $updated_at) + ->addValue('dateModified', $updated_at) + ->addValue('datePublished', $updated_at) + ->setDescription($seo_des) + ->setImages([$movie_thumb_url,$movie_poster_url]) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Director.php b/src/Models/Director.php new file mode 100644 index 0000000..09fc6f4 --- /dev/null +++ b/src/Models/Director.php @@ -0,0 +1,192 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('directors.movies.index', $params); + } + + protected function titlePattern(): string + { + return Setting::get('site_director_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_director_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_director_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->getTitle(); + $seo_des = Str::limit($this->getDescription(), 150, '...'); + $seo_key = $this->getKeywords(); + $movie_thumb_url = ''; + $movie_poster_url = ''; + $updated_at = ''; + if(count($this->movies)) { + $movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url; + $movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url; + $updated_at = $this->movies->last()->updated_at; + } + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $updated_at) + ->addProperty('url', $getUrl) + ->setDescription($seo_des) + ->addImages([$movie_thumb_url, $movie_poster_url]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->addValue('dateCreated', $updated_at) + ->addValue('dateModified', $updated_at) + ->addValue('datePublished', $updated_at) + ->setDescription($seo_des) + ->setImages([$movie_thumb_url, $movie_poster_url]) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Episode.php b/src/Models/Episode.php new file mode 100644 index 0000000..2c68e8f --- /dev/null +++ b/src/Models/Episode.php @@ -0,0 +1,212 @@ +movie_id, setting('site_cache_ttl', 5 * 60), function () { + return $this->movie; + }); + + $params = []; + $site_routes_movie = setting('site_routes_episode', '/phim/{movie}/{episode}-{id}'); + if (strpos($site_routes_movie, '{movie}')) $params['movie'] = $movie->slug; + if (strpos($site_routes_movie, '{movie_id}')) $params['movie_id'] = $movie->id; + if (strpos($site_routes_movie, '{episode}')) $params['episode'] = $this->slug; + if (strpos($site_routes_movie, '{id}')) $params['id'] = $this->id; + + return route('episodes.show', $params); + } + + public function openEpisode($crud = false) + { + return ' Open it'; + } + + protected function titlePattern(): string + { + return Setting::get('site_episode_watch_title', ''); + } + + public function generateSeoTags() + { + $movie_thumb_url = filter_var($this->movie->thumb_url, FILTER_VALIDATE_URL) ? $this->movie->thumb_url : request()->root() . $this->movie->thumb_url; + $movie_poster_url = filter_var($this->movie->poster_url, FILTER_VALIDATE_URL) ? $this->movie->poster_url : request()->root() . $this->movie->poster_url; + $movie_description = Str::limit(strip_tags($this->movie->content), 150, '...'); + $episode_getUrl = $this->getUrl(); + $getTitle = $this->getTitle(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($getTitle, false) + ->setDescription($movie_description) + ->addKeyword($this->movie->tags()->pluck('name')->toArray()) + ->addMeta('article:published_time', $this->updated_at->toW3CString(), 'property') + ->addMeta('article:section', $this->movie->categories->pluck('name')->join(","), 'property') + ->addMeta('article:tag', $this->movie->tags->pluck('name')->join(","), 'property') + ->setCanonical($episode_getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setType('video.episode') + ->setSiteName($site_meta_siteName) + ->setTitle($getTitle, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('url', $episode_getUrl) + ->addProperty('updated_time', $this->movie->updated_at) + ->setDescription($movie_description) + ->addImages([$movie_thumb_url,$movie_poster_url]) + ->setVideoEpisode([ + 'actor' => $this->movie->actors->pluck('name')->join(","), + 'director' => $this->movie->directors->pluck('name')->join(","), + 'duration' => $this->movie->episode_time, + 'release_date' => $this->created_at, + 'tag' => $this->movie->tags->pluck('name')->join(", "), + 'series' => 'video.tv_show' + ]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($getTitle, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($movie_description) + ->setUrl($episode_getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->addValue('dateCreated', $this->created_at) + ->addValue('dateModified', $this->updated_at) + ->addValue('datePublished', $this->created_at) + ->setTitle($getTitle, false) + ->setType('Movie') + ->setDescription($movie_description) + ->setImages([$movie_thumb_url,$movie_poster_url]) + ->addValue('aggregateRating', [ + '@type' => 'AggregateRating', + 'bestRating' => "10", + 'worstRating' => "1", + 'ratingValue' => $this->movie->getRatingStar(), + 'reviewCount' => $this->movie->getRatingCount() + ]) + ->addValue('director', count($this->movie->directors) ? $this->movie->directors->map(function ($director) { + return ['@type'=> 'Person', 'name' => $director->name]; + }) : "") + ->addValue('actor', count($this->movie->actors) ? $this->movie->actors->map(function ($actor) { + return ['@type'=> 'Person', 'name' => $actor->name]; + }) : "") + ->setUrl($episode_getUrl); + // ->addValue($key, $value); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + foreach ($this->movie->regions as $item) { + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $item->name, + 'item' => $item->getUrl(), + ]); + } + foreach ($this->movie->categories as $item) { + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $item->name, + 'item' => $item->getUrl(), + ]); + } + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => $this->movie->name, + 'item' => $this->movie->getUrl() + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 4, + 'name' => "Tập " . $this->name, + ]); + + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movie() + { + return $this->belongsTo(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Menu.php b/src/Models/Menu.php new file mode 100644 index 0000000..58e03e5 --- /dev/null +++ b/src/Models/Menu.php @@ -0,0 +1,76 @@ +belongsTo(static::class, 'parent_id'); + } + + public function children() + { + return $this->hasMany(static::class, 'parent_id'); + } + + /** + * Get all menu items, in a hierarchical collection. + * Only supports 2 levels of indentation. + */ + public static function getTree() + { + $menu = self::fromCache()->all()->sortBy('lft'); + + if ($menu->count()) { + foreach ($menu as $k => $menu_item) { + $menu_item->children = collect([]); + + foreach ($menu as $i => $menu_subitem) { + if ($menu_subitem->parent_id == $menu_item->id) { + $menu_item->children->push($menu_subitem); + + // remove the subitem for the first level + $menu = $menu->reject(function ($item) use ($menu_subitem) { + return $item->id == $menu_subitem->id; + }); + } + } + } + } + + return $menu; + } + + public function url() + { + switch ($this->type) { + case 'external_link': + return $this->link; + break; + + case 'internal_link': + return is_null($this->link) ? '#' : url($this->link); + break; + + default: //page_link + if ($this->page) { + return url($this->page->slug); + } + break; + } + } +} diff --git a/src/Models/Movie.php b/src/Models/Movie.php new file mode 100644 index 0000000..2436484 --- /dev/null +++ b/src/Models/Movie.php @@ -0,0 +1,308 @@ +timestamps = request('timestamps') ?: false; + }); + } + + public static function primaryCacheKey(): string + { + $site_routes = setting('site_routes_movie', '/phim/{movie}'); + if (strpos($site_routes, '{movie}')) return 'slug'; + if (strpos($site_routes, '{id}')) return 'id'; + return 'slug'; + } + + public function getUrl() + { + $params = []; + $site_routes = setting('site_routes_movie', '/phim/{movie}'); + if (strpos($site_routes, '{movie}')) $params['movie'] = $this->slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('movies.show', $params); + } + + public function getThumbUrl() + { + if (setting('site_image_proxy_enable', false)) { + $image_url = filter_var($this->thumb_url, FILTER_VALIDATE_URL) ? $this->thumb_url : url('/') . $this->thumb_url; + return str_replace('{image_url}', urlencode($image_url), setting('site_image_proxy_url', '')); + } + return $this->thumb_url; + } + + public function getPosterUrl() + { + if ($this->poster_url) { + if (setting('site_image_proxy_enable', false)) { + $image_url = filter_var($this->poster_url, FILTER_VALIDATE_URL) ? $this->poster_url : url('/') . $this->poster_url; + return str_replace('{image_url}', urlencode($image_url), setting('site_image_proxy_url', '')); + } + return $this->poster_url; + } + return $this->getThumbUrl(); + } + + public function getRatingStar() + { + return number_format($this->rating_star > 0 ? $this->rating_star : 8, 1); + } + + public function getRatingCount() + { + return $this->rating_count >= 1 ? $this->rating_count : 1; + } + + public function generateSeoTags() + { + $movie_thumb_url = filter_var($this->thumb_url, FILTER_VALIDATE_URL) ? $this->thumb_url : request()->root() . $this->thumb_url; + $movie_poster_url = filter_var($this->poster_url, FILTER_VALIDATE_URL) ? $this->poster_url : request()->root() . $this->poster_url; + $seo_des = Str::limit(strip_tags($this->content), 150, '...'); + $getTitle = $this->getTitle(); + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($getTitle, false) + ->setDescription($seo_des) + ->addKeyword($this->tags()->pluck('name')->toArray()) + ->addMeta('article:published_time', $this->updated_at->toW3CString(), 'property') + ->addMeta('article:section', $this->categories->pluck('name')->join(","), 'property') + ->addMeta('article:tag', $this->tags->pluck('name')->join(","), 'property') + ->setCanonical($getUrl) + ->setPrev(url('/')) + ->setPrev(url('/')); + + if ($this->type === 'single') { + OpenGraph::setType('video.movie') + ->setTitle($getTitle, false) + ->setDescription($seo_des) + ->setSiteName($site_meta_siteName) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $this->updated_at) + ->addProperty('url', $getUrl) + ->addImages([$movie_thumb_url,$movie_poster_url]) + ->setVideoMovie([ + 'actor' => $this->actors->pluck('name')->join(","), + 'director' => $this->directors->pluck('name')->join(","), + 'duration' => $this->episode_time, + 'release_date' => $this->created_at, + 'tag' => $this->tags->pluck('name')->join(", ") + ]); + } else { + OpenGraph::setType('video.tv_show') + ->setTitle($getTitle, false) + ->setDescription($seo_des) + ->setSiteName($site_meta_siteName) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $this->updated_at) + ->addProperty('url', $getUrl) + ->addImages([$movie_thumb_url,$movie_poster_url]) + ->setVideoTVShow([ + 'actor' => $this->actors->pluck('name')->join(","), + 'director' => $this->directors->pluck('name')->join(","), + 'duration' => $this->episode_time, + 'release_date' => $this->created_at, + 'tag' => $this->tags->pluck('name')->join(", ") + ]); + } + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($getTitle, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->addValue('dateCreated', $this->created_at) + ->addValue('dateModified', $this->updated_at) + ->addValue('datePublished', $this->created_at) + ->setTitle($getTitle, false) + ->setType('Movie') + ->setDescription($seo_des) + ->setImages([$movie_thumb_url, $movie_poster_url]) + ->addValue('aggregateRating', [ + '@type' => 'AggregateRating', + 'bestRating' => "10", + 'worstRating' => "1", + 'ratingValue' => $this->getRatingStar(), + 'reviewCount' => $this->getRatingCount() + ]) + ->addValue('director', count($this->directors) ? $this->directors->map(function ($director) { + return ['@type' => 'Person', 'name' => $director->name]; + }) : "") + ->addValue('actor', count($this->actors) ? $this->actors->map(function ($actor) { + return ['@type' => 'Person', 'name' => $actor->name]; + }) : "") + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + foreach ($this->regions as $item) { + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $item->name, + 'item' => $item->getUrl(), + ]); + } + foreach ($this->categories as $item) { + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $item->name, + 'item' => $item->getUrl(), + ]); + } + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => $this->name + ]); + + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + public function openView($crud = false) + { + return ' View'; + } + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function categories() + { + return $this->belongsToMany(Category::class); + } + + public function regions() + { + return $this->belongsToMany(Region::class); + } + + public function directors() + { + return $this->belongsToMany(Director::class); + } + + public function actors() + { + return $this->belongsToMany(Actor::class); + } + + public function tags() + { + return $this->belongsToMany(Tag::class); + } + + public function episodes() + { + return $this->hasMany(Episode::class); + } + + public function studios() + { + return $this->belongsToMany(Studio::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + public function getStatus() + { + $statuses = [ + 'trailer' => __('Sắp chiếu'), + 'ongoing' => __('Đang chiếu'), + 'completed' => __('Hoàn thành') + ]; + return $statuses[$this->status]; + } + + protected function titlePattern(): string + { + return Setting::get('site_movie_title', ''); + } + + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Region.php b/src/Models/Region.php new file mode 100644 index 0000000..4c0fbd6 --- /dev/null +++ b/src/Models/Region.php @@ -0,0 +1,192 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('regions.movies.index', $params, $withDomain); + } + + protected function titlePattern(): string + { + return Setting::get('site_region_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_region_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_region_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->seo_title ?: $this->getTitle(); + $seo_des = Str::limit($this->seo_des ?: $this->getDescription(), 150, '...'); + $seo_key = $this->seo_key ?: $this->getKeywords(); + $movie_thumb_url = ''; + $movie_poster_url = ''; + $updated_at = ''; + if(count($this->movies)) { + $movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url; + $movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url; + $updated_at = $this->movies->last()->updated_at; + } + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $updated_at) + ->addProperty('url', $getUrl) + ->setDescription($seo_des) + ->addImages([$movie_thumb_url, $movie_poster_url]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->addValue('dateCreated', $updated_at) + ->addValue('dateModified', $updated_at) + ->addValue('datePublished', $updated_at) + ->setDescription($seo_des) + ->setImages([$movie_thumb_url, $movie_poster_url]) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Studio.php b/src/Models/Studio.php new file mode 100644 index 0000000..ecafd3c --- /dev/null +++ b/src/Models/Studio.php @@ -0,0 +1,149 @@ +slug); + } + + protected function titlePattern(): string + { + return Setting::get('site_studio_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_region_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_region_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->getTitle(); + $seo_des = Str::limit($this->getDescription(), 150, '...'); + $seo_key = $this->getKeywords(); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($this->getUrl()) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + // ->addMeta($meta, $value, 'property'); + + OpenGraph::setSiteName(setting('site_meta_siteName')) + ->setTitle($seo_title, false) + ->addProperty('type', 'movie') + ->addProperty('locale', 'vi-VN') + ->addProperty('url', $this->getUrl()) + ->setDescription($seo_des) + ->addImages([$this->thumb_url, $this->poster_url]); + + TwitterCard::setSite(setting('site_meta_siteName')) + ->setTitle($seo_title, false) + ->setType('movie') + ->setImage($this->thumb_url) + ->setDescription($seo_des) + ->setUrl($this->getUrl()); + // ->addValue($key, $value); + + JsonLdMulti::newJsonLd() + ->setSite(setting('site_meta_siteName')) + ->setTitle($seo_title, false) + ->setType('movie') + ->setDescription($seo_des) + ->setUrl($this->getUrl()); + // ->addValue($key, $value); + } + + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Tag.php b/src/Models/Tag.php new file mode 100644 index 0000000..f1ac18a --- /dev/null +++ b/src/Models/Tag.php @@ -0,0 +1,191 @@ +slug; + if (strpos($site_routes, '{id}')) $params['id'] = $this->id; + return route('tags.movies.index', $params); + } + + protected function titlePattern(): string + { + return Setting::get('site_tag_title', ''); + } + + protected function descriptionPattern(): string + { + return Setting::get('site_tag_des', ''); + } + + protected function keywordsPattern(): string + { + return Setting::get('site_tag_key', ''); + } + + public function generateSeoTags() + { + $seo_title = $this->getTitle(); + $seo_des = Str::limit($this->getDescription(), 150, '...'); + $seo_key = $this->getKeywords(); + $movie_thumb_url = ''; + $movie_poster_url = ''; + $updated_at = ''; + if(count($this->movies)) { + $movie_thumb_url = filter_var($this->movies->last()->thumb_url, FILTER_VALIDATE_URL) ? $this->movies->last()->thumb_url : request()->root() . $this->movies->last()->thumb_url; + $movie_poster_url = filter_var($this->movies->last()->poster_url, FILTER_VALIDATE_URL) ? $this->movies->last()->poster_url : request()->root() . $this->movies->last()->poster_url; + $updated_at = $this->movies->last()->updated_at; + } + $getUrl = $this->getUrl(); + $site_meta_siteName = setting('site_meta_siteName'); + + SEOMeta::setTitle($seo_title, false) + ->setDescription($seo_des) + ->addKeyword([$seo_key]) + ->setCanonical($getUrl) + ->setPrev(request()->root()) + ->setPrev(request()->root()); + + OpenGraph::setSiteName($site_meta_siteName) + ->setType('website') + ->setTitle($seo_title, false) + ->addProperty('locale', 'vi-VN') + ->addProperty('updated_time', $updated_at) + ->addProperty('url', $getUrl) + ->setDescription($seo_des) + ->addImages([$this->thumb_url, $this->poster_url]); + + TwitterCard::setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('summary') + ->setImage($movie_thumb_url) + ->setDescription($seo_des) + ->setUrl($getUrl); + + JsonLdMulti::newJsonLd() + ->setSite($site_meta_siteName) + ->setTitle($seo_title, false) + ->setType('WebPage') + ->addValue('dateCreated', $updated_at) + ->addValue('dateModified', $updated_at) + ->addValue('datePublished', $updated_at) + ->setDescription($seo_des) + ->setImages([$movie_thumb_url, $movie_poster_url]) + ->setUrl($getUrl); + + $breadcrumb = []; + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 1, + 'name' => 'Home', + 'item' => url('/') + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 2, + 'name' => $this->name, + 'item' => $getUrl + ]); + array_push($breadcrumb, [ + '@type' => 'ListItem', + 'position' => 3, + 'name' => "Trang " . (request()->get('page') ?: 1), + ]); + JsonLdMulti::newJsonLd() + ->setType('BreadcrumbList') + ->addValue('name', '') + ->addValue('description', '') + ->addValue('itemListElement', $breadcrumb); + } + + + /* + |-------------------------------------------------------------------------- + | RELATIONS + |-------------------------------------------------------------------------- + */ + + public function movies() + { + return $this->belongsToMany(Movie::class); + } + + /* + |-------------------------------------------------------------------------- + | SCOPES + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | ACCESSORS + |-------------------------------------------------------------------------- + */ + + /* + |-------------------------------------------------------------------------- + | MUTATORS + |-------------------------------------------------------------------------- + */ +} diff --git a/src/Models/Theme.php b/src/Models/Theme.php new file mode 100644 index 0000000..458a010 --- /dev/null +++ b/src/Models/Theme.php @@ -0,0 +1,140 @@ + 'array', + ]; + + public static function getActivatedTheme(): ?self + { + return Theme::where('active', true)->first() ?: Theme::first(); + } + + public function getVersionAttribute() + { + if (!\Composer\InstalledVersions::isInstalled($this->package_name)) { + return 'Unknown'; + } + + return \PackageVersions\Versions::getVersion($this->package_name); + } + + public function getOptionsAttribute() + { + $allThemes = config('themes', []); + + if (!isset($allThemes[strtolower($this->name)]['options'])) { + return []; + } + + return $allThemes[strtolower($this->name)]['options']; + } + + public function editBtn($crud = false) + { + return 'id}/edit") . '" class="btn btn-primary">Edit'; + } + + public function deleteBtn($crud = false) + { + if ($this->getVersionAttribute() === 'Unknown') { + + $template = << + {csrfField} + + + EOT; + $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/delete"), $template); + $html = str_replace("{csrfField}", csrf_field(), $html); + $html = str_replace("{display_name}", $this->display_name, $html); + + return $html; + } + return ''; + } + + public function activeBtn($crud = false) + { + $template = << + {csrfField} + + + EOT; + + $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/active"), $template); + $html = str_replace("{csrfField}", csrf_field(), $html); + $html = str_replace("{display_name}", $this->display_name, $html); + + if ($this->active) { + $html = str_replace("{name}", 'Re-Activate', $html); + $html = str_replace("{btnType}", 'btn-secondary', $html); + } else { + $html = str_replace("{name}", 'Activate', $html); + $html = str_replace("{btnType}", 'btn-primary', $html); + } + + return $html; + } + + public function resetBtn($crud = false) + { + $template = << + {csrfField} + + + EOT; + + $html = str_replace("{actionRoute}", backpack_url("theme/{$this->id}/reset"), $template); + $html = str_replace("{csrfField}", csrf_field(), $html); + $html = str_replace("{btnType}", 'btn-warning', $html); + $html = str_replace("{name}", 'Reset', $html); + + return $html; + } + + public function active() + { + static::where('active', true)->update(['active' => false]); + + $publishTags = config('themes', [])[$this->name]['publishes'] ?? []; + + foreach ($publishTags as $tag) { + Artisan::call('vendor:publish', [ + '--tag' => $tag, + '--force' => true + ]); + } + + return $this->update(['active' => true]); + } +} diff --git a/src/Models/User.php b/src/Models/User.php new file mode 100644 index 0000000..7073832 --- /dev/null +++ b/src/Models/User.php @@ -0,0 +1,13 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse user'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create user'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update user'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete user'); + } + +} diff --git a/src/Policies/CatalogPolicy.php b/src/Policies/CatalogPolicy.php new file mode 100644 index 0000000..8d0b1e2 --- /dev/null +++ b/src/Policies/CatalogPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse catalog'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create catalog'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update catalog'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete catalog'); + } + +} diff --git a/src/Policies/CategoryPolicy.php b/src/Policies/CategoryPolicy.php new file mode 100644 index 0000000..2a02860 --- /dev/null +++ b/src/Policies/CategoryPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse category'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create category'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update category'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete category'); + } + +} diff --git a/src/Policies/CrawlSchedulePolicy.php b/src/Policies/CrawlSchedulePolicy.php new file mode 100644 index 0000000..2fcc6b6 --- /dev/null +++ b/src/Policies/CrawlSchedulePolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse crawl schedule'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create crawl schedule'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update crawl schedule'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete crawl schedule'); + } + +} diff --git a/src/Policies/DirectorPolicy.php b/src/Policies/DirectorPolicy.php new file mode 100644 index 0000000..d71286b --- /dev/null +++ b/src/Policies/DirectorPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse director'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create director'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update director'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete director'); + } + +} diff --git a/src/Policies/EpisodePolicy.php b/src/Policies/EpisodePolicy.php new file mode 100644 index 0000000..b4afb0f --- /dev/null +++ b/src/Policies/EpisodePolicy.php @@ -0,0 +1,37 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse episode'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create episode'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update episode'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete episode'); + } +} diff --git a/src/Policies/MenuPolicy.php b/src/Policies/MenuPolicy.php new file mode 100644 index 0000000..eb6d678 --- /dev/null +++ b/src/Policies/MenuPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse menu'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create menu'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update menu'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete menu'); + } + +} diff --git a/src/Policies/MoviePolicy.php b/src/Policies/MoviePolicy.php new file mode 100644 index 0000000..ad59178 --- /dev/null +++ b/src/Policies/MoviePolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse movie'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create movie'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update movie'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete movie'); + } + +} diff --git a/src/Policies/PermissionPolicy.php b/src/Policies/PermissionPolicy.php new file mode 100644 index 0000000..d282792 --- /dev/null +++ b/src/Policies/PermissionPolicy.php @@ -0,0 +1,39 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse permission'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create permission'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update permission'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete permission'); + } + +} diff --git a/src/Policies/RegionPolicy.php b/src/Policies/RegionPolicy.php new file mode 100644 index 0000000..1a5e233 --- /dev/null +++ b/src/Policies/RegionPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse region'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create region'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update region'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete region'); + } + +} diff --git a/src/Policies/RolePolicy.php b/src/Policies/RolePolicy.php new file mode 100644 index 0000000..b38ee71 --- /dev/null +++ b/src/Policies/RolePolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse role'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create role'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update role'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete role'); + } + +} diff --git a/src/Policies/StudioPolicy.php b/src/Policies/StudioPolicy.php new file mode 100644 index 0000000..830b71f --- /dev/null +++ b/src/Policies/StudioPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse studio'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create studio'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update studio'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete studio'); + } + +} diff --git a/src/Policies/TagPolicy.php b/src/Policies/TagPolicy.php new file mode 100644 index 0000000..4118989 --- /dev/null +++ b/src/Policies/TagPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse tag'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create tag'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update tag'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete tag'); + } + +} diff --git a/src/Policies/UserPolicy.php b/src/Policies/UserPolicy.php new file mode 100644 index 0000000..b4d2df1 --- /dev/null +++ b/src/Policies/UserPolicy.php @@ -0,0 +1,38 @@ +hasRole('Admin')) { + return true; + } + } + + public function browse($user) + { + return $user->hasPermissionTo('Browse user'); + } + + public function create($user) + { + return $user->hasPermissionTo('Create user'); + } + + public function update($user, $entry) + { + return $user->hasPermissionTo('Update user'); + } + + public function delete($user, $entry) + { + return $user->hasPermissionTo('Delete user'); + } + +} diff --git a/src/Requests/ActorRequest.php b/src/Requests/ActorRequest.php new file mode 100644 index 0000000..7603680 --- /dev/null +++ b/src/Requests/ActorRequest.php @@ -0,0 +1,59 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + $this->name_md5 = md5($this->name); + + return [ + 'name' => ['required', 'max:255', new UniqueName('actors', 'name', 'name_md5', 'id', $this->id)], + 'slug' => 'max:255|unique:actors,slug,' . $this->id . ',id', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/CatalogRequest.php b/src/Requests/CatalogRequest.php new file mode 100644 index 0000000..44a4a53 --- /dev/null +++ b/src/Requests/CatalogRequest.php @@ -0,0 +1,60 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|min:5|max:255', + 'slug' => 'max:255|unique:catalogs,slug,' . $this->id . ',id', + 'value' => 'string', + 'seo_title' => 'string|max:255', + 'seo_des' => 'string|max:255', + 'seo_key' => 'string|max:255', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/CategoryRequest.php b/src/Requests/CategoryRequest.php new file mode 100644 index 0000000..36de56f --- /dev/null +++ b/src/Requests/CategoryRequest.php @@ -0,0 +1,59 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|min:5|max:255', + 'slug' => 'max:255|unique:categories,slug,' . $this->id . ',id', + 'seo_title' => 'string|max:255', + 'seo_des' => 'string|max:255', + 'seo_key' => 'string|max:255', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/CrawlScheduleRequest.php b/src/Requests/CrawlScheduleRequest.php new file mode 100644 index 0000000..2e462db --- /dev/null +++ b/src/Requests/CrawlScheduleRequest.php @@ -0,0 +1,56 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'type' => 'required', + 'fields' => 'required' + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/DirectorRequest.php b/src/Requests/DirectorRequest.php new file mode 100644 index 0000000..b985569 --- /dev/null +++ b/src/Requests/DirectorRequest.php @@ -0,0 +1,59 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + $this->name_md5 = md5($this->name); + + return [ + 'name' => ['required', 'max:255', new UniqueName('directors', 'name', 'name_md5', 'id', $this->id)], + 'slug' => 'max:255|unique:directors,slug,' . $this->id . ',id', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/MenuRequest.php b/src/Requests/MenuRequest.php new file mode 100644 index 0000000..b7a9272 --- /dev/null +++ b/src/Requests/MenuRequest.php @@ -0,0 +1,57 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|max:255', + 'type' => 'required', + 'link' => 'required|max:2048' + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/MovieRequest.php b/src/Requests/MovieRequest.php new file mode 100644 index 0000000..f803e11 --- /dev/null +++ b/src/Requests/MovieRequest.php @@ -0,0 +1,59 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|max:512', + 'origin_name' => 'required|max:512', + 'slug' => 'max:255|unique:movies,slug,' . $this->id . ',id', + 'type' => 'required|in:single,series', + 'status' => 'required|in:trailer,ongoing,completed', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/RegionRequest.php b/src/Requests/RegionRequest.php new file mode 100644 index 0000000..e024bd4 --- /dev/null +++ b/src/Requests/RegionRequest.php @@ -0,0 +1,59 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|min:5|max:255', + 'slug' => 'max:255|unique:regions,slug,' . $this->id . ',id', + 'seo_title' => 'string|max:255', + 'seo_des' => 'string|max:255', + 'seo_key' => 'string|max:255', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/StudioRequest.php b/src/Requests/StudioRequest.php new file mode 100644 index 0000000..e940fee --- /dev/null +++ b/src/Requests/StudioRequest.php @@ -0,0 +1,56 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => 'required|string|max:512', + 'slug' => 'max:255|unique:studios,slug,' . $this->id . ',id', + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Requests/TagRequest.php b/src/Requests/TagRequest.php new file mode 100644 index 0000000..28488bf --- /dev/null +++ b/src/Requests/TagRequest.php @@ -0,0 +1,57 @@ +check(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'name' => ['required', 'max:255', new UniqueName('tags', 'name', 'name_md5', 'id', $this->id)], + ]; + } + + /** + * Get the validation attributes that apply to the request. + * + * @return array + */ + public function attributes() + { + return [ + // + ]; + } + + /** + * Get the validation messages that apply to the request. + * + * @return array + */ + public function messages() + { + return [ + // + ]; + } +} diff --git a/src/Rules/UniqueName.php b/src/Rules/UniqueName.php new file mode 100644 index 0000000..ace2003 --- /dev/null +++ b/src/Rules/UniqueName.php @@ -0,0 +1,51 @@ +table = $table; + $this->md5Field = $md5Field; + $this->excludeField = $excludeField; + $this->excludeVal = $excludeVal; + $this->nameField = $nameField; + } + + /** + * Determine if the validation rule passes. + * + * @param string $attribute + * @param mixed $value + * @return bool + */ + public function passes($attribute, $value) + { + return DB::table($this->table)->where($this->excludeField, '!=', $this->excludeVal)->where($this->md5Field, md5($value))->doesntExist(); + } + + /** + * Get the validation error message. + * + * @return string + */ + public function message() + { + return ":attribute must be unique"; + } +} diff --git a/src/Theme.php b/src/Theme.php new file mode 100644 index 0000000..3a2fd53 --- /dev/null +++ b/src/Theme.php @@ -0,0 +1,43 @@ +payload = $payload; + + $this->name = ThemeModel::getActivatedTheme()->name; + + if (is_null($this->name)) { + throw new \Exception("Not found any theme. Please install and active one.");; + } + + $this->themePath = $this->namespace . '::' . $this->name; + } + + public function render($template, array $data = []) + { + $viewPath = sprintf("%s.%s", $this->themePath, $template); + if (!view()->exists($viewPath)) { + throw new Exception("Theme {$this->name}'s {$template} view is not installed. Please check your installation"); + } + + return view($viewPath, array_merge($this->payload, $data)); + } + + public function addPayload(array $data) + { + $this->payload = array_merge($this->payload, $data); + } +} diff --git a/src/Traits/ActorLog.php b/src/Traits/ActorLog.php new file mode 100644 index 0000000..c862627 --- /dev/null +++ b/src/Traits/ActorLog.php @@ -0,0 +1,19 @@ +user_id = auth('backpack')->id() ?: $instance->user_id; + $instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username; + }); + + static::updating(function ($instance) { + $instance->user_id = auth('backpack')->id() ?: $instance->user_id; + $instance->user_name = auth('backpack')->user() ? auth('backpack')->user()->name : $instance->username; + }); + } +} diff --git a/src/Traits/HasDescription.php b/src/Traits/HasDescription.php new file mode 100644 index 0000000..840f8b2 --- /dev/null +++ b/src/Traits/HasDescription.php @@ -0,0 +1,37 @@ +descriptionPattern(); + + preg_match_all('/{.*?}/', $pattern, $vars); + + foreach ($vars[0] as $var) { + try { + $x = str_replace('{', '', $var); + $x = str_replace('}', '', $x); + $keys = explode('.', (string) $x); + $data = $this; + foreach ($keys as $key) { + $data = $data->{$key}; + } + $pattern = str_replace($var, $data, $pattern); + } catch (\Exception $e) { + } + } + + return $pattern; + } +} diff --git a/src/Traits/HasFactory.php b/src/Traits/HasFactory.php new file mode 100644 index 0000000..17e91f3 --- /dev/null +++ b/src/Traits/HasFactory.php @@ -0,0 +1,20 @@ +keywordsPattern(); + + preg_match_all('/{.*?}/', $pattern, $vars); + + foreach ($vars[0] as $var) { + try { + $x = str_replace('{', '', $var); + $x = str_replace('}', '', $x); + $keys = explode('.', (string) $x); + $data = $this; + foreach ($keys as $key) { + $data = $data->{$key}; + } + $pattern = str_replace($var, $data, $pattern); + } catch (\Exception $e) { + } + } + + return $pattern; + } +} diff --git a/src/Traits/HasTitle.php b/src/Traits/HasTitle.php new file mode 100644 index 0000000..73b3c12 --- /dev/null +++ b/src/Traits/HasTitle.php @@ -0,0 +1,37 @@ +titlePattern(); + + preg_match_all('/{.*?}/', $pattern, $vars); + + foreach ($vars[0] as $var) { + try { + $x = str_replace('{', '', $var); + $x = str_replace('}', '', $x); + $keys = explode('.', (string) $x); + $data = $this; + foreach ($keys as $key) { + $data = $data->{$key}; + } + $pattern = str_replace($var, $data, $pattern); + } catch (\Exception $e) { + } + } + + return $pattern; + } +} diff --git a/src/Traits/HasUniqueName.php b/src/Traits/HasUniqueName.php new file mode 100644 index 0000000..b796e7f --- /dev/null +++ b/src/Traits/HasUniqueName.php @@ -0,0 +1,24 @@ +name_md5 = md5($instance->name); + }); + + static::updating(function ($instance) { + $instance->name_md5 = md5($instance->name); + }); + } +} diff --git a/src/Traits/Operations/BulkDeleteOperation.php b/src/Traits/Operations/BulkDeleteOperation.php new file mode 100644 index 0000000..5c05432 --- /dev/null +++ b/src/Traits/Operations/BulkDeleteOperation.php @@ -0,0 +1,46 @@ + $routeName.'.bulkDelete', + 'uses' => $controller.'@bulkDelete', + 'operation' => 'bulkDelete', + ]); + } + + protected function setupBulkDeleteDefaults() + { + $this->crud->allowAccess('bulkDelete'); + + $this->crud->operation('bulkDelete', function () { + $this->crud->loadDefaultOperationSettingsFromConfig(); + }); + + $this->crud->operation('list', function () { + $this->crud->enableBulkActions(); + $this->crud->addButton('bottom', 'bulk_delete', 'view', 'crud::buttons.bulk_delete'); + }); + } + + public function bulkDelete() + { + $this->crud->hasAccessOrFail('bulkDelete'); + $entries = request()->input('entries', []); + $deletedEntries = []; + + foreach ($entries as $key => $id) { + if ($entry = $this->crud->model->find($id)) { + $deletedEntries[] = $entry->delete(); + } + } + + return $deletedEntries; + } +} diff --git a/src/Traits/Sluggable.php b/src/Traits/Sluggable.php new file mode 100644 index 0000000..1987971 --- /dev/null +++ b/src/Traits/Sluggable.php @@ -0,0 +1,34 @@ +slug)) { + $slug = Str::slug($instance->name) ?: $instance->name; + $instance->slug = static::where('slug', $slug)->exists() + ? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100)) + : $slug; + } + }); + + static::updating(function ($instance) { + if (empty($instance->slug)) { + $slug = Str::slug($instance->name) ?: $instance->name; + $instance->slug = static::where('slug', $slug)->exists() + ? sprintf("%s-%s%s", $slug, floor(microtime(true) * 1000), rand(1, 100)) + : $slug; + } + }); + } +} diff --git a/src/VsMovServiceProvider.php b/src/VsMovServiceProvider.php new file mode 100644 index 0000000..842d978 --- /dev/null +++ b/src/VsMovServiceProvider.php @@ -0,0 +1,229 @@ + ActorPolicy::class, + Catalog::class => CatalogPolicy::class, + Category::class => CategoryPolicy::class, + Region::class => RegionPolicy::class, + Director::class => DirectorPolicy::class, + Tag::class => TagPolicy::class, + Studio::class => StudioPolicy::class, + Movie::class => MoviePolicy::class, + Episode::class => EpisodePolicy::class, + Menu::class => MenuPolicy::class, + CrawlSchedule::class => CrawlSchedulePolicy::class + ]; + } + + public function register() + { + $this->mergeConfigFrom(__DIR__ . '/../config/config.php', 'vsmov'); + + $this->mergeBackpackConfigs(); + + $this->mergeCkfinderConfigs(); + + $this->mergePolicies(); + } + + public function boot() + { + $this->registerPolicies(); + + try { + foreach (glob(__DIR__ . '/Helpers/*.php') as $filename) { + require_once $filename; + } + } catch (\Exception $e) { + //throw $e; + } + + $this->loadRoutesFrom(__DIR__ . '/../routes/admin.php'); + + $this->app->booted(function () { + $this->loadThemeRoutes(); + $this->loadScheduler(); + }); + + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); + + $this->loadViewsFrom(__DIR__ . '/../resources/views/core/', 'vsmov'); + + $this->loadViewsFrom(__DIR__ . '/../resources/views/themes', 'themes'); + + $this->publishFiles(); + + $this->commands([ + InstallCommand::class, + CreateUser::class, + GenerateMenuCommand::class, + ChangeDomainEpisodeCommand::class, + ]); + + $this->bootSeoDefaults(); + } + + protected function publishFiles() + { + $backpack_menu_contents_view = [ + __DIR__ . '/../resources/views/core/base/' => resource_path('views/vendor/vsmov/base/'), + __DIR__ . '/../resources/views/core/crud/' => resource_path('views/vendor/vsmov/crud/'), + ]; + + $players = [ + __DIR__ . '/../resources/assets/js/hls.min.js' => public_path('js/hls.min.js'), + __DIR__ . '/../resources/assets/js/jwplayer-8.9.3.js' => public_path('js/jwplayer-8.9.3.js'), + __DIR__ . '/../resources/assets/js/jwplayer.hlsjs.min.js' => public_path('js/jwplayer.hlsjs.min.js'), + ]; + + $this->publishes($backpack_menu_contents_view, 'cms_menu_content'); + $this->publishes($players, 'players'); + + $this->publishes([ + __DIR__ . '/../config/config.php' => config_path('vsmov.php') + ], 'config'); + } + + protected function mergeBackpackConfigs() + { + config(['backpack.base.styles' => array_merge(config('backpack.base.styles', []), [ + 'packages/select2/dist/css/select2.css', + 'packages/select2-bootstrap-theme/dist/select2-bootstrap.min.css' + ])]); + + config(['backpack.base.scripts' => array_merge(config('backpack.base.scripts', []), [ + 'packages/select2/dist/js/select2.full.min.js' + ])]); + + config(['backpack.base.middleware_class' => array_merge(config('backpack.base.middleware_class', []), [ + \Backpack\CRUD\app\Http\Middleware\UseBackpackAuthGuardInsteadOfDefaultAuthGuard::class, + ])]); + + config(['cachebusting_string' => \PackageVersions\Versions::getVersion('vsmov/crud')]); + + config(['backpack.base.project_logo' => 'VsMovCMS']); + config(['backpack.base.developer_name' => 'vsmov']); + config(['backpack.base.developer_link' => 'mailto:vsmov@gmail.com']); + config(['backpack.base.show_powered_by' => false]); + } + + protected function mergeCkfinderConfigs() + { + config(['ckfinder.authentication' => CKFinderAuth::class]); + config(['ckfinder.backends.default' => config('vsmov.ckfinder.backends')]); + } + + protected function mergePolicies() + { + config(['backpack.permissionmanager.policies.permission' => PermissionPolicy::class]); + config(['backpack.permissionmanager.policies.role' => RolePolicy::class]); + config(['backpack.permissionmanager.policies.user' => UserPolicy::class]); + } + + protected function bootSeoDefaults() + { + config([ + 'seotools.meta.defaults.title' => setting('site_homepage_title'), + 'seotools.meta.defaults.description' => setting('site_meta_description'), + 'seotools.meta.defaults.keywords' => [setting('site_meta_keywords')], + 'seotools.meta.defaults.canonical' => url("/") + ]); + + config([ + 'seotools.opengraph.defaults.title' => setting('site_homepage_title'), + 'seotools.opengraph.defaults.description' => setting('site_meta_description'), + 'seotools.opengraph.defaults.type' => 'website', + 'seotools.opengraph.defaults.url' => url("/"), + 'seotools.opengraph.defaults.site_name' => setting('site_meta_siteName'), + 'seotools.opengraph.defaults.images' => [setting('site_meta_image')], + ]); + + config([ + 'seotools.twitter.defaults.card' => 'website', + 'seotools.twitter.defaults.title' => setting('site_homepage_title'), + 'seotools.twitter.defaults.description' => setting('site_meta_description'), + 'seotools.twitter.defaults.url' => url("/"), + 'seotools.twitter.defaults.site' => setting('site_meta_siteName'), + 'seotools.twitter.defaults.image' => setting('site_meta_image'), + ]); + + config([ + 'seotools.json-ld.defaults.title' => setting('site_homepage_title'), + 'seotools.json-ld.defaults.type' => 'WebPage', + 'seotools.json-ld.defaults.description' => setting('site_meta_description'), + 'seotools.json-ld.defaults.images' => setting('site_meta_image'), + ]); + } + + protected function loadThemeRoutes() + { + try { + $activatedTheme = Theme::getActivatedTheme(); + if ($activatedTheme && file_exists($routeFile = base_path('vendor/' . $activatedTheme->package_name . '/routes/web.php'))) { + $this->loadRoutesFrom($routeFile); + } + } catch (\Exception $e) { + // Log + } + } + + protected function loadScheduler() + { + $schedule = $this->app->make(Schedule::class); + + $schedule->call(function () { + DB::table('movies')->update(['view_day' => 0]); + })->daily(); + $schedule->call(function () { + DB::table('movies')->update(['view_week' => 0]); + })->weekly(); + $schedule->call(function () { + DB::table('movies')->update(['view_month' => 0]); + })->monthly(); + } +} \ No newline at end of file diff --git a/tests/databases/DatabaseTesting.php b/tests/databases/DatabaseTesting.php new file mode 100644 index 0000000..13619c4 --- /dev/null +++ b/tests/databases/DatabaseTesting.php @@ -0,0 +1,59 @@ +call([ + CategoriesTableSeeder::class, + RegionsTableSeeder::class, + ThemesTableSeeder::class, + MenusTableSeeder::class, + SettingsTableSeeder::class, + ]); + + Actor::factory(100)->create(); + Director::factory(100)->create(); + Tag::factory(100)->create(); + + for ($i = 1; $i < 1000; $i++) { + Movie::factory(1) + ->state([ + 'publish_year' => rand(2018, 2022) + ]) + ->hasAttached(Region::all()->random()) + ->hasAttached(Category::all()->random(3)) + ->hasAttached(Actor::all()->random(rand(1, 5))) + ->hasAttached(Director::all()->random(1)) + ->hasAttached(Tag::all()->random(5)) + ->has(Episode::factory(5)->state([ + 'server' => 'Vietsub #1', + 'type' => 'embed', + 'link' => 'https://aa.nguonphimmoi.com/20220309/2918_589b816d/index.m3u8' + ])) + ->create(); + } + } +} diff --git a/webpack.mix.js b/webpack.mix.js new file mode 100644 index 0000000..861ba0b --- /dev/null +++ b/webpack.mix.js @@ -0,0 +1,14 @@ +const mix = require('laravel-mix'); + +/* + |-------------------------------------------------------------------------- + | Mix Asset Management + |-------------------------------------------------------------------------- + | + | Mix provides a clean, fluent API for defining some Webpack build steps + | for your Laravel applications. By default, we are compiling the CSS + | file for the application as well as bundling up all the JS files. + | + */ + +