我用 jellyfin 服务器上的 django 制作了一个 streaming 应用程序,我使用视频 js 来播放我的视频媒体。问题是,当我尝试播放超过 1 小时且更长的视频时,会花费疯狂的时间,似乎视频是先下载然后播放的,而且我无法推进媒体并将其放在我的位置想,我首先怀疑有一个名为 preload 的 video js 选项,所以我尝试了值 'none','metadata' 和 'auto',但没有任何结果实际上,一位同事给了我一个猜测也许 django 不支持这种功能!谁能证实这一点吗? django 的解决方案是什么?
例如,这是我获取剧集类型电影的功能:views.py
def episode_detail(request, episode_id):
user_id = request.session.get('jellyfin_user_id')
access_token = request.session.get('jellyfin_access_token')
if not user_id or not access_token:
return redirect('jellyfin_login')
# try:
# user = JellyfinUser.objects.get(jellyfin_user_id=user_id)
# except JellyfinUser.DoesNotExist:
# return redirect('jellyfin_login')
headers = {
'X-Emby-Token': settings.JELLYFIN_API_KEY
}
episode_url = f"{settings.JELLYFIN_URL}/Users/{user_id}/Items/{episode_id}"
episode_response = requests.get(episode_url, headers=headers)
if episode_response.status_code != 200:
return render(request, 'error.html', context={'error': 'Unable to fetch episode details'})
episode = episode_response.json()
if episode['Type'] == 'Movie':
people = episode.get('People', [])
if people is None:
people = []
genres_url = f"{settings.JELLYFIN_URL}/Genres?ParentId={episode_id}"
genres_response = requests.get(genres_url, headers=headers)
genres = genres_response.json().get('Items', []) if genres_response.status_code == 200 else []
episode['Genres'] = [genre['Name'] for genre in genres]
studio_url = f"{settings.JELLYFIN_URL}/Studios?ParentId={episode_id}"
studio_response = requests.get(studio_url, headers=headers)
studios = studio_response.json().get('Items', []) if studio_response.status_code == 200 else []
episode['Studios'] = [studio['Name'] for studio in studios]
directors = [person['Name'] for person in people if person['Type'] == 'Director']
episode['Directors'] = directors
actors = []
for person in people:
if person['Type'] == 'Actor':
actor_image_url = f"{settings.JELLYFIN_URL}/Persons/{person['Name']}/Images/Primary"
actor_image_url_response = requests.get(actor_image_url, headers=headers)
if actor_image_url_response.status_code == 200:
person['ImageURL'] = actor_image_url
else:
person['ImageURL'] = static("library/images/default/default-user.jpg")
actor_info = {
'name': person['Name'],
'role': person['Role'],
'image': person['ImageURL'],
'id': person['Id'],
}
actors.append(actor_info)
episode['Actors'] = actors
writers = [person['Name'] for person in people if person['Type'] == 'Writer']
episode['Writers'] = writers
producers = [person['Name'] for person in people if person['Type'] == 'Producer']
episode['Producers'] = producers
similar_url = f"{settings.JELLYFIN_URL}/Items/{episode_id}/Similar"
similar_response = requests.get(similar_url, headers=headers)
similar_episodes = similar_response.json().get('Items', []) if similar_response.status_code == 200 else []
for item in similar_episodes:
item['ImageURL'] = f"{settings.JELLYFIN_URL}/Items/{item['Id']}/Images/Primary"
episode['SimilarEpisodes'] = similar_episodes
episode['VideoURL'] = f"{settings.JELLYFIN_URL}/Videos/{episode['Id']}/stream"
episode['ImageURL'] = f"{settings.JELLYFIN_URL}/Items/{episode['Id']}/Images/Primary"
episode['BackdropURL'] = f"{settings.JELLYFIN_URL}/Items/{episode['Id']}/Images/Backdrop"
episode['CommunityRating'] = episode.get('CommunityRating', 'N/A')
episode['Overview'] = episode.get('Overview', 'Aucune description disponible')
episode['Duration'] = format_duration(episode['RunTimeTicks'])
print("NO FILE")
user_data = episode.get('UserData', {})
if user_data is None:
user_data = {}
episode['IsFavorite'] = user_data.get('IsFavorite', False)
print(episode['Type'])
return render(request, 'episode_detail.html', context={'episode': episode})
这是我的 Episode_detail.html:episode_detail.html
{% extends 'base.html' %}
{% block title %} {{ episode.Name }} {% endblock %}
{% block style %}
<!-- My Styles -->
{% endblock %}
{% block content %}
<div class="container mb-5">
{% if episode.Type == 'Movie' %}
<div class="row">
<!-- AFFICHE DU FILM -->
<div class="col-md-4">
<img src="{{ episode.ImageURL }}" class="img-fluid movie-poster shadow-lg" alt="{{ episode.Name }}">
</div>
<!-- INFOS DU FILM -->
<div class="col-md-8">
<h1 class="text-white">{{ episode.Name }}</h1>
<div class="d-flex align-items-center">
<span class="production-year">{{ episode.ProductionYear }}</span>
<span class="duration">{{ episode.Duration }}</span>
<span class="note-commu">
<span>{{ episode.CommunityRating|floatformat:1 }}</span>
<span class="blue-star"><i class="fa-solid fa-star"></i></span>
</span>
</div>
<!-- SYNOPSIS DU FILM -->
{% if episode.Overview %}
<div class="mt-3">
<h4 class="section-title"><b>Synopsis</b></h4>
<p>{{ episode.Overview }}</p>
</div>
{% endif %}
<!-- DETAILS DU FILM -->
<div class="mt-3">
{% if episode.Genres or episode.Studios or episode.Directors or episode.Actors %}
<h4 class="section-title"><b>Details</b></h4>
{% endif %}
{% if episode.Genres %}<p><strong>Genre:</strong> {{ episode.Genres|join:", " }}</p>{% endif %}
{% if episode.Studios %}<p><strong>Studios:</strong> {{ episode.Studios|join:", " }}</p>{% endif %}
{% if episode.Directors %}<p><strong>Réalisateurs :</strong> {{episode.Directors|join:", " }}</p>{% endif %}
{% if episode.Writers %}<p><strong>Scénaristes :</strong> {{episode.Writers|join:", " }}</p>{% endif %}
{% if episode.Producers %}<p><strong>Producteurs:</strong> {{ episode.Producers|join:", " }}</p>{% endif %}
{% if episode.Actors_name %}<p><strong>Acteurs:</strong> {{ episode.Actors_name|join:", " }}</p>{% endif %}
</div>
<!-- SECTION VIDEO DU FILM -->
<div class="mt-5">
<video
id="my-movie-video"
class="video-js vjs-big-play-centered vjs-fluid vjs-fill"
controls
preload="none"
poster="{{ episode.BackdropURL }}"
data-setup="{}"
>
<source src="{{ episode.VideoURL }}" type="video/mp4" />
<source src="{{ episode.VideoURL }}" type="video/webm" />
<source src="{{ episode.VideoURL }}" type="video/avi" />
<source src="{{ episode.VideoURL }}" type="video/mkv" />
<p class="vjs-no-js">
To view this video please enable JavaScript, and consider upgrading to a
web browser that
<a href="https://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
</p>
</video>
</div>
</div>
</div>
</div>
{% endblock %}
检查您的 MP4 的元数据是否位于前面(而不是文件的后面)。“似乎视频先下载然后播放需要疯狂的时间”
您可以使用
此站点 检查 MP4(向下滚动到 MP4 原子位置 部分)。
如果它显示
“未优化”,则元数据位于后面(并且还需要完整下载)。
MP4 moov 快速启动修复建议。
当您自己提供字节(通过流式传输)时,您必须自己处理查找。“我无法将介质推进并放到我想要的位置,””
这意味着监听
seek 事件(由 HTML5 视频标签触发)并为该查找点提供新字节。您的 MP4 必须是碎片 MP4才能通过字节流轻松查找。当您的应用程序获得一个搜索点(以秒为单位)时,您将计算需要读取哪个文件(如果按时间分隔)或哪个字节范围(如果所有视频持续时间都在一个文件内)。您的流媒体现在改为发送这些字节。这些字节将是一个 MP4 片段,表示请求的“查找”时间的数据。