主頁 > .NET開發 > DjangoRestFramework:如何計算視頻持續時間的百分比?

DjangoRestFramework:如何計算視頻持續時間的百分比?

2022-03-07 21:24:47 .NET開發

在我的專案中,我有一個視頻部分,我想在其中計算用戶觀看時間的百分比。通過以下網址可以訪問視頻的詳細資訊

網址:視頻/video_id 輸出:

"video": {
                "id": "84e7288c-dc09-44aa-850c-08546a98ffde",
                "deleted": null,
                "datetime_created": "02/04/2022 06:56 AM",
                "datetime_updated": "02/04/2022 06:56 AM",
                "video_name": "video name3",
                "description": "description about video",
                "duration": "00:33:20",
                "create_date": "02/04/2022 06:56 AM",
                "video_type": "micro",
                "file_url": "https://vimeo.com/216763352",
                "general_status": "high",
                "review_status": "draft",
                "video_number": "VD6129",
                "created_by": null
            },

"duration": "00:33:20" 是視頻的總時長。如果以總秒數傳遞時間,如何計算用戶正在觀看的視頻時間百分比

{
    "time":200
}

uj5u.com熱心網友回復:

好吧,我最近做了類似的事情,我的任務是計算視頻觀看時間并相應地給予分數。我還被要求不要給出觀看視頻時間的百分比和分數。我使用合并演算法來合并重疊間隔。您可以根據您的任務要求自定義代碼,因為您可能不會像我一樣被要求給用戶積分并進行獨特的 100% 準確計算,這是我所做的:

模型.py

from django.db import models
from django.apps import apps
from django.db.models import Sum, F, Subquery
from django.db.models.functions import Coalesce
from django.utils.translation import ugettext_lazy as _
from django.dispatch import receiver
from django.db.models.signals import post_save

from common.models import BaseUser
from helpers.models import BaseModel


class LessonTypeChoices(models.TextChoices):
    video = "video", _("Video")
    task = "task", _("Task")
    exam = "exam", _("Exam")
    book = "book", _("Book")
    audiobook = "audiobook", _("Audio book")


class Lesson(BaseModel):
    course = models.ForeignKey(
        "courses.Course",
        on_delete=models.CASCADE,
        related_name="lessons",
        verbose_name=_("course"),
    )
    type = models.CharField(_("type"), max_length=32, choices=LessonTypeChoices.choices)
    title = models.CharField(_("title"), max_length=256)
    description = models.TextField(_("description"))
    points = models.IntegerField(_("points"), default=0)
    order = models.IntegerField(_("order"), default=0)

    def __str__(self):
        return f"{self.title} - {self.type}"

    class Meta:
        db_table = "lesson"
        verbose_name = _("lesson")
        verbose_name_plural = _("lessons")


@receiver(post_save, sender=Lesson)
def add_course_point(sender, instance, created, **kwargs):
    """
    Increment course points by lesson points when lesson is created
    """
    Course = apps.get_model("courses.Course")
    Course.objects.filter(id=instance.course_id).update(
        points=Subquery(
            Course.objects.filter(id=instance.course_id)
            .annotate(sum_points=Sum("lessons__points"))
            .values("sum_points")
        )
    )

class LessonProgress(BaseModel):
    lesson = models.ForeignKey(
        Lesson,
        on_delete=models.CASCADE,
        related_name="lesson_progress",
        verbose_name=_("lesson"),
    )
    user = models.ForeignKey(
        BaseUser,
        on_delete=models.CASCADE,
        related_name="lesson_progress",
        verbose_name=_("user"),
    )
    type = models.CharField(_("type"), max_length=32, choices=LessonTypeChoices.choices)
    percentage = models.FloatField(_("progress percentage"), default=0)
    points = models.FloatField(_("points"), default=0)
    is_locked = models.BooleanField(_("lesson is locked"), default=True)
    is_completed = models.BooleanField(_("lesson is completed"), default=False)
    last_progress = models.IntegerField(_("last progress"), default=0)

    class Meta:
        unique_together = ("lesson", "user")
        db_table = "lesson_progress"
        verbose_name = _("lesson progress")
        verbose_name_plural = _("lesson progress")

    def set_locked(self, instance, user):
        """
        Update lessons' locked status
        """
        percentage = self.get_percentage(instance, user)

        for index, lesson in enumerate(instance.lessons.all().order_by("order")):
            if index in [0, 1] or percentage / ((index   1) - 2) >= 80:
                lesson.lesson_progress.update(is_locked=False)
            else:
                lesson.lesson_progress.update(is_locked=True)

    @staticmethod
    def get_percentage(instance, user):
        """
        Calculate average percentage of completed lessons
        """
        percentage = (
            instance.lessons.all()
            .aggregate(
                percentage=Coalesce(
                    Sum(
                        "lesson_progress__percentage",
                        filter=models.Q(lesson_progress__user=user),
                    ),
                    0,
                )
            )
            .get("percentage")
        )
        return percentage

    @staticmethod
    def is_complete(percentage):
        """
        decide whether lesson is completed or not
        """
        if percentage >= 90:
            return True
        return False

    @staticmethod
    def calculate_percentage(length, progress):
        """
        Calculate the watched video or submitted exam answer percentage
        """
        return progress / length * 100

    @staticmethod
    def calculate_points(
        instance,
        percentage,
    ):
        """
        Calculate earned points by lesson progress percentage
        """
        return instance.points / 100 * percentage

    @staticmethod
    def user_points(user, points, is_expired):
        """
        Add points to user
        """
        if not is_expired:
            user.score  = points
            user.save()

    @staticmethod
    def task_progress_points(instance, percentage, is_completed, points, is_expired):
        """
        Update task lesson progress -> percentage, is_completed, points
        """
        instance.percentage  = percentage
        instance.is_completed = is_completed

        if not is_expired:
            instance.points  = points

        instance.save()

    @staticmethod
    def exam_video_progress_points(
        instance, percentage, last_progress, is_completed, points, is_expired
    ):
        """
        Update exam video lesson progress -> percentage, last_progress, is_completed, points
        """
        instance.percentage  = percentage
        instance.last_progress = last_progress
        instance.is_completed = is_completed

        if not is_expired:
            instance.points  = points

        instance.save()

    @staticmethod
    def merge(intervals, progress_before):
        """
        merge queryset with each other, remove overlapping intervals and create
        """
        bulk_list = []

        for progress in intervals:
            # merge overlapping intervals
            if bulk_list and progress.start_progress <= bulk_list[-1].end_progress:
                bulk_list[-1].end_progress = max(
                    bulk_list[-1].end_progress, progress.end_progress
                )
                bulk_list[-1].progress = (
                    max(bulk_list[-1].end_progress, progress.end_progress)
                    - bulk_list[0].start_progress
                )
                bulk_list[-1].video_length = max(
                    bulk_list[-1].video_length, progress.video_length
                )

            else:
                # add merged interval object to bulk_list
                bulk_list.append(
                    LessonVideoProgress(
                        lesson_progress_id=progress.lesson_progress_id,
                        video_length=progress.video_length,
                        start_progress=progress.start_progress,
                        end_progress=progress.end_progress,
                        progress=progress.end_progress - progress.start_progress,
                    )
                )

        # delete all interval objects
        intervals.delete()

        # create intervals from bulk_list
        LessonVideoProgress.objects.bulk_create(bulk_list)

        # calculate the duration seconds of new intervals
        progress_after = intervals.aggregate(progress_sum=Sum("progress")).get(
            "progress_sum"
        )

        # get the watched duration seconds -> subtracting old progress seconds by new progress seconds
        return float(progress_after - progress_before)

    @staticmethod
    def progress_before_merge(queryset):
        # calculate the progress duration seconds sum before creating new video progress instance
        return queryset.aggregate(progress_sum=Coalesce(Sum("progress"), 0)).get(
            "progress_sum"
        )

    @staticmethod
    def create_lesson_video_progress(
        progress_id, video_length, start_progress, end_progress
    ):
        # create new video progress instance
        LessonVideoProgress.objects.create(
            lesson_progress_id=progress_id,
            video_length=video_length,
            start_progress=start_progress,
            end_progress=end_progress,
        )

    @staticmethod
    def round_percentage(percentage, progress_percentage):
        # round the given percentages to 100 in case it exceeds it
        return percentage - ((progress_percentage   percentage) - 100)


@receiver(post_save, sender=LessonProgress)
def run_lessons(sender, instance, **kwargs):
    if instance.pk:
        instance.set_locked(instance.lesson.course, instance.user)


class LessonVideoProgress(BaseModel):
    lesson_progress = models.ForeignKey(
        LessonProgress, on_delete=models.CASCADE, related_name="lesson_video_progress"
    )
    video_length = models.DecimalField(
        _("video length"), max_digits=19, decimal_places=3
    )
    progress = models.DecimalField(
        _("progress duration"), default=0, max_digits=19, decimal_places=3
    )
    start_progress = models.DecimalField(
        _("start progress"), max_digits=19, decimal_places=3
    )
    end_progress = models.DecimalField(
        _("end progress"), max_digits=19, decimal_places=3
    )

    class Meta:
        db_table = "lesson_video_progress"
        verbose_name = _("lesson video progress")
        verbose_name_plural = _("lesson video progress")

    def __str__(self):
        return f"{self.progress}"

視圖.py

class LessonVideoExamSubmitView(generics.GenericAPIView):
    queryset = LessonProgress.objects.all()
    serializer_class = serializers.LessonVideoExamSubmitSerializer

    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(
            data=request.data, context={"request": request}
        )
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

序列化程式.py

class LessonVideoExamSubmitSerializer(serializers.Serializer):
    lesson_id = serializers.IntegerField()
    video_length = serializers.FloatField()
    start_progress = serializers.FloatField()
    end_progress = serializers.FloatField()
    is_expired = serializers.BooleanField(default=False)

    def create(self, validated_data):
        # get lesson progress for given lesson id
        progress = LessonProgress.objects.get(
            lesson_id=validated_data.get("lesson_id"), user=self.context["request"].user
        )

        # get the current video progress before merging with other progresses
        progress_before_merge = progress.progress_before_merge(
            progress.lesson_video_progress
        )

    # create new video progress for given intervals
    progress.create_lesson_video_progress(
        progress.id,
        validated_data.get("video_length"),
        validated_data.get("start_progress"),
        validated_data.get("end_progress"),
    )

    # merge created video progress objects with existing objects in the database
    progress_merge = progress.merge(
        progress.lesson_video_progress.all().order_by("start_progress"),
        progress_before_merge,
    )

    # pass video length and merged objects duration in seconds and get watched video percentage
    percentage = progress.calculate_percentage(
        validated_data.get("video_length"), progress_merge
    )

    if progress.percentage   percentage >= 100:
        """
        add progress percentage and calculated percentage, round the sum to 100
        """
        percentage = progress.round_percentage(percentage, progress.percentage)

    # get points to the lesson by passing the percentage
    points = progress.calculate_points(progress.lesson, percentage)

    # add points to user
    progress.user_points(progress.user, points, validated_data.get("is_expired"))

    # get completed status by sum of progress percentages
    is_completed = progress.is_complete(progress.percentage   percentage)

    # update lesson progress object
    progress.exam_video_progress_points(
        progress,
        percentage,
        validated_data.get("end_progress"),
        is_completed,
        points,
        validated_data.get("is_expired"),
    )

    return validated_data

請注意,您可以為自己的視頻計算邏輯優化和洗掉不必要的部分。這也可以用于音頻計算邏輯。我通常不分享源代碼,但只是因為我真的很想幫忙,我做到了,干杯)

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/438680.html

標籤:python-3.x django django注册

上一篇:借助for回圈將pandas行中的字串值替換為數字

下一篇:在不重新排列列的情況下提取重復并在python中找到cumsum

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more