Skip to content

Commit

Permalink
Adding video viewers page
Browse files Browse the repository at this point in the history
  • Loading branch information
efonsecab committed Apr 16, 2024
1 parent 17fedf2 commit 2915fec
Show file tree
Hide file tree
Showing 9 changed files with 162 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public static class FairPlayTubeRoutes
public static class CreatorRoutes
{
public const string MyVideos = $"/Creator/{nameof(MyVideos)}";
public const string MyVideoViewers = $"/Creator/{nameof(MyVideoViewers)}";
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class VideoInfoModel : IListModel
public string[]? VideoTopics { get; set; }
public string? EnglishCaptions { get; set; }
public int LifetimeSessions { get; set; }
public int LifetimeViewers { get; set; }
public TimeSpan LifetimeWatchTime { get; set; }
public string? PublishedUrl { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FairPlayCombined.Models.FairPlayTube.VideoViewer
{
public class VideoViewerModel
{
public string? VideoId { get; set; }
public string? VideoName { get; set; }
public string? Username { get; set; }
public long TotalSessions { get; set; }
public double TotalTimeWatched { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ CancellationToken cancellationToken
VideoVisibilityId = p.VideoVisibilityId,
ThumbnailUrl = p.ThumbnailUrl,
YouTubeVideoId = p.YouTubeVideoId,
LifetimeViewers = p.VideoWatchTime.Select(p=>p.WatchedByApplicationUserId).Distinct().Count(),
LifetimeSessions = p.VideoWatchTime.Count,
LifetimeWatchTime = TimeSpan.FromSeconds(p.VideoWatchTime.Sum(p=>p.WatchTime))
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using FairPlayCombined.DataAccess.Data;
using FairPlayCombined.Models.FairPlayTube.VideoInfo;
using FairPlayCombined.Models.FairPlayTube.VideoViewer;
using FairPlayCombined.Models.Pagination;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using System.Threading.Tasks;

namespace FairPlayCombined.Services.FairPlayTube
{
public partial class VideoViewerService(
IDbContextFactory<FairPlayCombinedDbContext> dbContextFactory,
ILogger<VideoViewerService> logger) : BaseService
{
public async Task<PaginationOfT<VideoViewerModel>> GetPaginatedVideoViewerInfoForUserIdAsync(
PaginationRequest paginationRequest,
string videoId,
string userId,
CancellationToken cancellationToken)
{
logger.LogInformation(message: "Start of method: {methodName}", nameof(GetPaginatedVideoViewerInfoForUserIdAsync));
PaginationOfT<VideoViewerModel> result = new();
var dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);
string orderByString = string.Empty;
if (paginationRequest.SortingItems?.Length > 0)
orderByString =
String.Join(",",
paginationRequest.SortingItems.Select(p => $"{p.PropertyName} {GetSortTypeString(p.SortType)}"));
var query = dbContext.VideoWatchTime
.Include(p=>p.VideoInfo)
.Include(p=>p.WatchedByApplicationUser)
.Where(p=>p.VideoInfo.ApplicationUserId == userId && p.VideoInfo.VideoId == videoId)
.GroupBy(p=>new
{
Username=p.WatchedByApplicationUser.UserName,
VideoId = p.VideoInfo.VideoId,
VideoName = p.VideoInfo.Name
})
.OrderByDescending(p=>p.Sum(x=>x.WatchTime))
.Select(p => new VideoViewerModel
{
TotalSessions = p.Count(),
TotalTimeWatched = p.Sum(p=>p.WatchTime),
Username = p.Key.Username,
VideoId = p.Key.VideoId,
VideoName = p.Key.VideoName
});
if (!String.IsNullOrEmpty(orderByString))
query = query.OrderBy(orderByString);
result.TotalItems = await query.CountAsync(cancellationToken);
result.PageSize = paginationRequest.PageSize;
result.TotalPages = (int)Math.Ceiling((decimal)result.TotalItems / result.PageSize);
result.Items = await query
.Skip(paginationRequest.StartIndex)
.Take(paginationRequest.PageSize)
.ToArrayAsync(cancellationToken);
return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@attribute [Route($"{Constants.Routes.FairPlayTubeRoutes.CreatorRoutes.MyVideoViewers}/{{VideoId}}")]

@using FairPlayCombined.Common
@using FairPlayCombined.Interfaces
@using FairPlayCombined.Models.FairPlayTube.VideoInfo
@using FairPlayCombined.Models.FairPlayTube.VideoViewer
@using FairPlayCombined.Models.Pagination
@using FairPlayCombined.Services.Common
@using FairPlayCombined.Services.FairPlayTube
@using FairPlayTube.Components.Spinners

@rendermode RenderMode.InteractiveServer
@inject VideoViewerService videoViewerService
@inject IUserProviderService userProviderService
<PageTitle>My Video Viewers</PageTitle>

<LoadingIndicator ShowSpinners="this.IsBusy"></LoadingIndicator>

<div class="@ThemeConfiguration.Grids.GridContainerCss">
<FluentDataGrid ItemsProvider="ItemsProvider" Pagination="this.paginationState">
<PropertyColumn Property="@( p=> p.Username)"></PropertyColumn>
<PropertyColumn Property="@( p=> p.VideoName)"></PropertyColumn>
<TemplateColumn Title="@nameof(VideoViewerModel.TotalTimeWatched)">
@TimeSpan.FromSeconds(context.TotalTimeWatched)
</TemplateColumn>
<PropertyColumn Property="@( p=> p.TotalSessions)"></PropertyColumn>
</FluentDataGrid>
</div>
<FluentPaginator State="this.paginationState"></FluentPaginator>

@code
{
[Parameter]
public string? VideoId { get; set; }
private bool IsBusy { get; set; }
private GridItemsProvider<VideoViewerModel>? ItemsProvider;
PaginationState paginationState = new()
{
ItemsPerPage = Constants.Pagination.PageSize
};
private CancellationTokenSource cancellationTokenSource = new();

protected override void OnInitialized()
{
this.IsBusy = true;
ItemsProvider = async req =>
{
StateHasChanged();
PaginationRequest paginationRequest = new()
{
PageSize = paginationState.ItemsPerPage,
StartIndex = req.StartIndex
};
var items = await videoViewerService
.GetPaginatedVideoViewerInfoForUserIdAsync(paginationRequest,
videoId:this.VideoId!,
userId: this.userProviderService!.GetCurrentUserId()!,
this.cancellationTokenSource.Token);
StateHasChanged();
var result = GridItemsProviderResult.From<VideoViewerModel>(items!.Items!, items.TotalItems);
return result;
};
this.IsBusy = false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
OnClick="@( ()=> OnCreateLinkedInArticleClicked(context))">
<i class="bi bi-file-richtext-fill"></i>
</FluentButton>
<FluentButton Type="ButtonType.Button" data-bs-toggle="tooltip" data-bs-placement="top" title="View My Video Viewers"
OnClick="@( () => OnViewMyVideoViewersClicked(context))">
<FluentIcon Value="@(new Icons.Regular.Size20.PeopleAudience())"></FluentIcon>
</FluentButton>
@if (!String.IsNullOrWhiteSpace(context.YouTubeVideoId))
{
<FluentButton Type="ButtonType.Button" data-bs-toggle="tooltip" data-bs-placement="top" title="Manage YouTube Captions"
Expand Down Expand Up @@ -132,6 +136,11 @@
StateHasChanged();
}

private void OnViewMyVideoViewersClicked(VideoInfoModel videoInfoModel)
{
this.navigationManager.NavigateTo($"{Constants.Routes.FairPlayTubeRoutes.CreatorRoutes.MyVideoViewers}/{videoInfoModel.VideoId}");
}

private void OnManageYouTubeCaptionsButtonClicked(VideoInfoModel videoInfoModel)
{
this.navigationManager.NavigateTo($"/Creator/VideoCaptions/VideoInfo{videoInfoModel.VideoInfoId}/YouTube/{videoInfoModel.YouTubeVideoId}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
</div>
<div>
<FluentLabel Typo="Typography.Body">@singleItem.Name</FluentLabel>
<FluentLabel Typo="Typography.Body">Views: @singleItem.LifetimeSessions</FluentLabel>
<FluentLabel Typo="Typography.Body">Lifetime Sessions: @singleItem.LifetimeSessions</FluentLabel>
<FluentLabel Typo="Typography.Body">Lifetime Viewers: @singleItem.LifetimeViewers</FluentLabel>
<FluentLabel Typo="Typography.Body">Watch Time(hh:mm:ss): @singleItem.LifetimeWatchTime</FluentLabel>
</div>
<div>
Expand Down
1 change: 1 addition & 0 deletions src/FairPlayCombinedSln/FairPlayTube/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@
builder.Services.AddTransient<PromptGeneratorService>();
builder.Services.AddTransient<VideoWatchTimeService>();
builder.Services.AddTransient<SupportedLanguageService>();
builder.Services.AddTransient<VideoViewerService>();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

Expand Down

0 comments on commit 2915fec

Please sign in to comment.