Skip to content

Commit

Permalink
Implement offline video playback for sonarr and RSS
Browse files Browse the repository at this point in the history
  • Loading branch information
Foxocube committed Jan 1, 2025
1 parent 76e071f commit e2a45ab
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 22 deletions.
2 changes: 1 addition & 1 deletion MediaFeeder/MediaFeeder/Components/Pages/Video.razor
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<Content>
@if (VideoObject != null && Frame != null)
{
<DynamicComponent Type="@Frame" Parameters="@(new Dictionary<string, object>() { { "VideoId", VideoObject.VideoId } })"/>
<DynamicComponent Type="@Frame" Parameters="@(new Dictionary<string, object>() { { "Video", VideoObject } })"/>

<AntDesign.Text Type="secondary">
@if (VideoObject.Views > 0)
Expand Down
1 change: 1 addition & 0 deletions MediaFeeder/MediaFeeder/MediaFeeder.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

<ItemGroup>
<PackageReference Include="AntDesign" Version="1.0.1"/>
<PackageReference Include="Blazored.Video" Version="1.0.1" />
<PackageReference Include="Grpc.AspNetCore" Version="2.67.0" />
<PackageReference Include="Grpc.AspNetCore.HealthChecks" Version="2.67.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.0"/>
Expand Down
28 changes: 25 additions & 3 deletions MediaFeeder/MediaFeeder/Providers/DownloadedVideoFrame.razor
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
@using Blazored.Video
@using AntDesign
@inherits VideoFrame

<h3>DownloadedVideoFrame</h3>

@code {

}
@if (Video != null)
{
@if (Video.DownloadedPath != null)
{
<BlazoredVideo CanPlay="CanPlay"
Ended="Ended"
CanPlayThrough="CanPlayThrough"
class="w-100"
controls="controls">
<source src="@Video.DownloadedPath" type="video/mp4"/>
</BlazoredVideo>
}
else
{
<h4>Video is not downloaded</h4>
}
}
else
{
<Skeleton/>
}
21 changes: 21 additions & 0 deletions MediaFeeder/MediaFeeder/Providers/DownloadedVideoFrame.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Blazored.Video.Support;

namespace MediaFeeder.Providers;

public partial class DownloadedVideoFrame
{
private void CanPlay(VideoState obj)
{
throw new NotImplementedException();
}

private void Ended(VideoState obj)
{
throw new NotImplementedException();
}

private void CanPlayThrough(VideoState obj)
{
throw new NotImplementedException();
}
}
9 changes: 9 additions & 0 deletions MediaFeeder/MediaFeeder/Providers/VideoFrame.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using MediaFeeder.Data.db;
using Microsoft.AspNetCore.Components;

namespace MediaFeeder.Providers;

public abstract class VideoFrame : ComponentBase
{
[Parameter] public Video? Video { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@inject IJSRuntime JsRuntime
@using Microsoft.JSInterop
@implements IDisposable
@implements IAsyncDisposable
@inherits VideoFrame

<div id="ytplayer" style="width: 100%; height: 80vh;"></div>
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

namespace MediaFeeder.Providers.Youtube;

public partial class YouTubeVideoFrame
public sealed partial class YouTubeVideoFrame
{
[Parameter] public string? VideoId { get; set; }
private IJSObjectReference? _youtubeCustomModule;
private IJSObjectReference? _youtubeLibraryModule;
private IJSObjectReference? _player;
private DotNetObjectReference<YouTubeVideoFrame>? _videoFrameRef;

protected override async Task OnAfterRenderAsync(bool firstRender)
Expand All @@ -17,14 +16,17 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
{
_youtubeLibraryModule = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "/iframe_api.js");
_youtubeCustomModule = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./Providers/Youtube/YouTubeVideoFrame.razor.js");
}
}

Console.WriteLine($"_youtubeLibraryModule: {JsonSerializer.Serialize(_youtubeLibraryModule)}");
Console.WriteLine($"_youtubeCustomModule: {JsonSerializer.Serialize(_youtubeCustomModule)}");
protected override async Task OnParametersSetAsync()
{
if (_player == null && Video != null)
{
ArgumentNullException.ThrowIfNull(_youtubeCustomModule);

_videoFrameRef ??= DotNetObjectReference.Create(this);
var player = await _youtubeCustomModule.InvokeAsync<object>("initPlayer", _videoFrameRef, VideoId);

Console.WriteLine($"player: {JsonSerializer.Serialize(player)}");
_player = await _youtubeCustomModule.InvokeAsync<IJSObjectReference>("initPlayer", _videoFrameRef, Video.VideoId);
}
}

Expand Down Expand Up @@ -79,30 +81,31 @@ public Task OnApiChange(IJSObjectReference target, JsonElement data)
}

[JSInvokable]
public Task OnPlayerStateChange(IJSObjectReference target, JsonElement data)
public async Task OnPlayerStateChange(IJSObjectReference target, JsonElement data)
{
Console.WriteLine($"State change: {JsonSerializer.Serialize(data)}");

var state = (PlayerState) data.GetInt32();
var state = (PlayerState)
data.GetInt32();

if (state == PlayerState.ENDED)
{
Console.WriteLine("Video finished!");
// setWatchedStatus(1);
Console.WriteLine("Video finished!");
}
else if (state == PlayerState.UNSTARTED)
{
// player.playVideo();
target.InvokeVoidAsync("playVideo");
await target.InvokeVoidAsync("playVideo");
}

return Task.CompletedTask;
}

public void Dispose()
public async ValueTask DisposeAsync()
{
_videoFrameRef?.Dispose();
_youtubeLibraryModule?.DisposeAsync();
_youtubeCustomModule?.DisposeAsync();
if (_player != null) await _player.DisposeAsync();
if (_youtubeLibraryModule != null) await _youtubeLibraryModule.DisposeAsync();
if (_youtubeCustomModule != null) await _youtubeCustomModule.DisposeAsync();
}

enum PlayerState
Expand Down

0 comments on commit e2a45ab

Please sign in to comment.