Skip to content

Commit fb6db98

Browse files
committed
Added New Features
- Uppy Companion Server - RTMP Server - Live Stream
1 parent 0e35103 commit fb6db98

26 files changed

+3743
-333
lines changed

.env.example

+4
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,7 @@ LARAVEL_WEBSOCKETS_SSL_PASSPHRASE=
5656

5757
FFMPEG_BINARIES="/usr/local/bin/ffmpeg"
5858
FFPROBE_BINARIES="/usr/local/bin/ffprobe"
59+
60+
RTMP_HOST=http://localhost:3000
61+
UPPY_COMPANION_URL=http://localhost:3020/companion
62+
RTMP_SERVER_URL=rtmp://localhost/live

README.md

+10-3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ LARAVEL_WEBSOCKETS_SSL_PASSPHRASE=
4747
4848
FFMPEG_BINARIES=
4949
FFPROBE_BINARIES=
50+
51+
RTMP_HOST=http://localhost:3000
52+
UPPY_COMPANION_URL=http://localhost:3020/companion
53+
RTMP_SERVER_URL=rtmp://localhost/live
5054
```
5155

5256
```
@@ -56,11 +60,14 @@ FFPROBE_BINARIES=
5660
'frame_from_seconds' => 3
5761
]
5862
```
59-
Start Laravel Websockets Server
63+
Start Laravel Websockets Server, RTMP Server, Uppy Companion Server
6064

6165
```
6266
php artisan websockets:serve
6367
php artisan queue:work
68+
69+
npm run rtmp-server
70+
npm run companion-server
6471
```
6572

6673
## Create Admin User
@@ -84,8 +91,8 @@ php artisan create:admin
8491
- [ ] Video Playlists
8592
- [ ] Video Player - Google IMA Pre Roll Plugin
8693
- [x] ~~Realtime Notifications ( Dis/Like, Un/Subscribe Channel, Comments )~~
87-
- [ ] Admin Panel
88-
- [ ] Companion - Uppy Standalone Server
94+
- [x] ~~Admin Panel~~
95+
- [x] ~~Companion - Uppy Standalone Server~~
8996

9097
## Credits
9198
- All Contributors
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
namespace App\Http\Livewire\Frontend\Channel;
4+
5+
use Livewire\Component;
6+
7+
class LiveProducer extends Component
8+
{
9+
public $channel_id;
10+
public $video_id;
11+
public $video;
12+
public $name;
13+
public $description;
14+
public $start;
15+
public $server_url;
16+
public $stream_key;
17+
18+
public function mount()
19+
{
20+
$this->video = auth()->user()->channels()->find($this->channel_id)->videos()->find($this->video_id);
21+
$this->name = $this->video->name;
22+
$this->description = $this->video->description;
23+
$this->start = $this->video->extra_attributes->get('go_live');
24+
$this->stream_key = $this->video->extra_attributes->get('stream_key');
25+
$this->server_url = env('RTMP_SERVER_URL');
26+
}
27+
28+
public function startLive($value)
29+
{
30+
$this->video->extra_attributes->set('go_live', $value);
31+
$this->start = $value;
32+
33+
$this->video->name = $this->name;
34+
$this->video->description = $this->description;
35+
$this->video->save();
36+
37+
$this->emit('startLive');
38+
}
39+
40+
public function render()
41+
{
42+
return view('livewire.frontend.channel.live-producer');
43+
}
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace App\Http\Livewire\Frontend\Channel\Modal;
4+
5+
use App\Models\Channel\Channel;
6+
use Illuminate\Support\Str;
7+
use Livewire\Component;
8+
use Livewire\WithFileUploads;
9+
use LivewireUI\Modal\ModalComponent;
10+
11+
class CreateStream extends ModalComponent
12+
{
13+
use WithFileUploads;
14+
15+
public $channel_id;
16+
public $name;
17+
public $description;
18+
public $photo;
19+
20+
public static function closeModalOnClickAway(): bool
21+
{
22+
return false;
23+
}
24+
25+
public function render()
26+
{
27+
return view('livewire.frontend.channel.modal.create-stream');
28+
}
29+
30+
public function submit()
31+
{
32+
$stream_key = Str::random(20);
33+
$filesystem = config('site.converted_file_driver');
34+
$streaming_url = "/live/{$stream_key}/index.m3u8";
35+
$media_id = Str::random(10);
36+
37+
$channel = Channel::find($this->channel_id);
38+
$video = $channel->videos()->create([
39+
'name' => $this->name,
40+
'description' => $this->description,
41+
'disk' => $filesystem,
42+
'media_id' => $media_id,
43+
'status' => 'ready',
44+
'streaming_url' => $streaming_url,
45+
'type' => 'live',
46+
'extra_attributes' => [
47+
'stream_key' => $stream_key,
48+
'go_live' => false
49+
]
50+
]);
51+
52+
if ($this->photo)
53+
{
54+
$this->photo->storeAs('converted/' . $video->media_id, $video->id . '.png', $video->disk);
55+
$video->thumbnail_url = "converted/{$video->media_id}/{$video->id}.png";
56+
$video->save();
57+
}
58+
59+
$this->redirectRoute('user.channels.live', ['channel_id' => $video->channel_id, 'video_id' => $video->id]);
60+
}
61+
}

app/Http/Livewire/Frontend/Channel/Table/VideosTable.php

+2
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ public function columns(): array
5454
Column::make(__('Name'), 'name')
5555
->sortable()
5656
->searchable(),
57+
Column::make(__('Type'), 'type'),
5758
Column::make(__('Status'), 'status'),
5859
Column::make(__('Views')),
5960
Column::make(__('Likes (vs. Dislikes)')),
61+
// Column::make(__('Scheduled At'), 'scheduled_at')->sortable(),
6062
Column::make(__('Created At'), 'created_at')->sortable(),
6163
Column::blank(),
6264
];

app/Listeners/TusEventListener.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ public function handleUploadCompleted($event)
3535
'duration' => $duration,
3636
'status' => 'notready',
3737
'disk' => $filesystem,
38-
'tus_id' => $tus
38+
'tus_id' => $tus,
39+
'type' => 'upload',
3940
]);
4041
}catch (\Exception $e) {
4142
Log::error($e->getMessage());

app/Models/Channel/Video.php

+21-2
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,42 @@
33
namespace App\Models\Channel;
44

55
use App\Models\Channel\Traits\VideoRelationship;
6+
use App\Models\HasSchemalessAttributes;
67
use Cklmercer\ModelSettings\HasSettings;
78
use Illuminate\Database\Eloquent\Factories\HasFactory;
89
use Illuminate\Database\Eloquent\Model;
10+
use Illuminate\Support\Facades\Storage;
911
use Jcc\LaravelVote\Traits\Votable;
1012
use Overtrue\LaravelLike\Traits\Likeable;
1113
use CyrildeWit\EloquentViewable\InteractsWithViews;
1214
use CyrildeWit\EloquentViewable\Contracts\Viewable;
1315
use Cog\Contracts\Ban\Bannable as BannableContract;
1416
use Cog\Laravel\Ban\Traits\Bannable;
17+
use Spatie\SchemalessAttributes\SchemalessAttributesTrait;
18+
use Illuminate\Database\Eloquent\Builder;
1519

1620
class Video extends Model implements Viewable, BannableContract
1721
{
18-
use HasFactory, Likeable, Votable, VideoRelationship, InteractsWithViews, HasSettings, Bannable;
22+
use HasFactory, Likeable, Votable, VideoRelationship,
23+
InteractsWithViews, HasSettings, Bannable, SchemalessAttributesTrait;
1924

2025
protected $fillable = [
2126
'tus_id', 'media_id', 'name', 'description', 'disk', 'path',
2227
'thumbnail_url', 'file_size', 'file_type', 'duration', 'progress', 'status',
23-
'streaming_url'
28+
'streaming_url', 'type', 'extra_attributes'
2429
];
30+
31+
protected $schemalessAttributes = [
32+
'extra_attributes',
33+
];
34+
35+
public function scopeWithExtraAttributes(): Builder
36+
{
37+
return $this->extra_attributes->modelScope();
38+
}
39+
40+
public function getVideoSourceAttribute()
41+
{
42+
return $this->type == 'upload' ? Storage::disk($this->disk)->url($this->streaming_url) : env('RTMP_HOST') . $this->streaming_url;
43+
}
2544
}

app/Observers/VideoObserver.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class VideoObserver
1313
*/
1414
public function created(Video $video)
1515
{
16-
dispatch(new StartConvert($video->id));
16+
if ($video->type == 'upload') dispatch(new StartConvert($video->id));
1717
}
1818

1919
/**

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"predis/predis": "^1.1",
3333
"pusher/pusher-php-server": "~3.0",
3434
"rappasoft/laravel-livewire-tables": "^1.10",
35+
"spatie/laravel-schemaless-attributes": "^1.8",
3536
"symfony/process": "^5.3",
3637
"watson/active": "^6.0"
3738
},

composer.lock

+67-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
class AddExtraAttributesColumnToVideosTable extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('videos', function (Blueprint $table) {
17+
$table->string('scheduled_at')->nullable();
18+
$table->string('type')->default('upload');
19+
$table->schemalessAttributes('extra_attributes');
20+
});
21+
}
22+
23+
/**
24+
* Reverse the migrations.
25+
*
26+
* @return void
27+
*/
28+
public function down()
29+
{
30+
Schema::table('videos', function (Blueprint $table) {
31+
$table->dropColumn('scheduled_at');
32+
$table->dropColumn('type');
33+
$table->dropColumn('extra_attributes');
34+
});
35+
}
36+
}

0 commit comments

Comments
 (0)