index streams and file size
This commit is contained in:
parent
a4d42573ef
commit
a17f05ef21
|
@ -146,6 +146,9 @@
|
||||||
"type": "keyword",
|
"type": "keyword",
|
||||||
"index": false
|
"index": false
|
||||||
},
|
},
|
||||||
|
"media_size": {
|
||||||
|
"type": "long"
|
||||||
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"analyzer": "english",
|
"analyzer": "english",
|
||||||
|
@ -239,6 +242,30 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"streams": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "keyword",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
"index": {
|
||||||
|
"type": "short",
|
||||||
|
"index": false
|
||||||
|
},
|
||||||
|
"codec": {
|
||||||
|
"type": "text"
|
||||||
|
},
|
||||||
|
"width": {
|
||||||
|
"type": "short"
|
||||||
|
},
|
||||||
|
"height": {
|
||||||
|
"type": "short"
|
||||||
|
},
|
||||||
|
"bitrate": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"sponsorblock": {
|
"sponsorblock": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"last_refresh": {
|
"last_refresh": {
|
||||||
|
|
|
@ -16,7 +16,10 @@ from home.src.index import playlist as ta_playlist
|
||||||
from home.src.index.generic import YouTubeItem
|
from home.src.index.generic import YouTubeItem
|
||||||
from home.src.index.subtitle import YoutubeSubtitle
|
from home.src.index.subtitle import YoutubeSubtitle
|
||||||
from home.src.index.video_constants import VideoTypeEnum
|
from home.src.index.video_constants import VideoTypeEnum
|
||||||
from home.src.index.video_streams import DurationConverter
|
from home.src.index.video_streams import (
|
||||||
|
DurationConverter,
|
||||||
|
MediaStreamExtractor,
|
||||||
|
)
|
||||||
from home.src.ta.helper import clean_string, randomizor
|
from home.src.ta.helper import clean_string, randomizor
|
||||||
from home.src.ta.ta_redis import RedisArchivist
|
from home.src.ta.ta_redis import RedisArchivist
|
||||||
from ryd_client import ryd_client
|
from ryd_client import ryd_client
|
||||||
|
@ -153,6 +156,7 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle):
|
||||||
self._add_stats()
|
self._add_stats()
|
||||||
self.add_file_path()
|
self.add_file_path()
|
||||||
self.add_player(media_path)
|
self.add_player(media_path)
|
||||||
|
self.add_streams(media_path)
|
||||||
if self.config["downloads"]["integrate_ryd"]:
|
if self.config["downloads"]["integrate_ryd"]:
|
||||||
self._get_ryd_stats()
|
self._get_ryd_stats()
|
||||||
|
|
||||||
|
@ -254,6 +258,17 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def add_streams(self, media_path=False):
|
||||||
|
"""add stream metadata"""
|
||||||
|
vid_path = self._get_vid_path(media_path)
|
||||||
|
media = MediaStreamExtractor(vid_path)
|
||||||
|
self.json_data.update(
|
||||||
|
{
|
||||||
|
"streams": media.extract_metadata(),
|
||||||
|
"media_size": media.get_file_size(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
def _get_vid_path(self, media_path=False):
|
def _get_vid_path(self, media_path=False):
|
||||||
"""get path of media file"""
|
"""get path of media file"""
|
||||||
if media_path:
|
if media_path:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""extract metadata from video streams"""
|
"""extract metadata from video streams"""
|
||||||
|
|
||||||
|
import json
|
||||||
import subprocess
|
import subprocess
|
||||||
|
from os import stat
|
||||||
|
|
||||||
|
|
||||||
class DurationConverter:
|
class DurationConverter:
|
||||||
|
@ -52,3 +54,79 @@ class DurationConverter:
|
||||||
duration_str = duration_str + "00:"
|
duration_str = duration_str + "00:"
|
||||||
duration_str = duration_str + str(secs).zfill(2)
|
duration_str = duration_str + str(secs).zfill(2)
|
||||||
return duration_str
|
return duration_str
|
||||||
|
|
||||||
|
|
||||||
|
class MediaStreamExtractor:
|
||||||
|
"""extract stream metadata"""
|
||||||
|
|
||||||
|
def __init__(self, media_path):
|
||||||
|
self.media_path = media_path
|
||||||
|
self.metadata = []
|
||||||
|
|
||||||
|
def extract_metadata(self):
|
||||||
|
"""entry point to extract metadata"""
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
"ffprobe",
|
||||||
|
"-v",
|
||||||
|
"quiet",
|
||||||
|
"-print_format",
|
||||||
|
"json",
|
||||||
|
"-show_streams",
|
||||||
|
"-show_format",
|
||||||
|
self.media_path,
|
||||||
|
]
|
||||||
|
result = subprocess.run(
|
||||||
|
cmd, capture_output=True, text=True, check=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.returncode != 0:
|
||||||
|
return self.metadata
|
||||||
|
|
||||||
|
streams = json.loads(result.stdout).get("streams")
|
||||||
|
for stream in streams:
|
||||||
|
self.process_stream(stream)
|
||||||
|
|
||||||
|
return self.metadata
|
||||||
|
|
||||||
|
def process_stream(self, stream):
|
||||||
|
"""parse stream to metadata"""
|
||||||
|
codec_type = stream.get("codec_type")
|
||||||
|
if codec_type == "video":
|
||||||
|
self._extract_video_metadata(stream)
|
||||||
|
elif codec_type == "audio":
|
||||||
|
self._extract_audio_metadata(stream)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
def _extract_video_metadata(self, stream):
|
||||||
|
"""parse video metadata"""
|
||||||
|
if "bit_rate" not in stream:
|
||||||
|
# is probably thumbnail
|
||||||
|
return
|
||||||
|
|
||||||
|
self.metadata.append(
|
||||||
|
{
|
||||||
|
"type": "video",
|
||||||
|
"index": stream["index"],
|
||||||
|
"codec": stream["codec_name"],
|
||||||
|
"width": stream["width"],
|
||||||
|
"height": stream["height"],
|
||||||
|
"bitrate": int(stream["bit_rate"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def _extract_audio_metadata(self, stream):
|
||||||
|
"""extract audio metadata"""
|
||||||
|
self.metadata.append(
|
||||||
|
{
|
||||||
|
"type": "audio",
|
||||||
|
"index": stream["index"],
|
||||||
|
"codec": stream["codec_name"],
|
||||||
|
"bitrate": int(stream["bit_rate"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_file_size(self):
|
||||||
|
"""get filesize in bytes"""
|
||||||
|
return stat(self.media_path).st_size
|
||||||
|
|
|
@ -56,20 +56,6 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>Youtube: Deactivated</p>
|
<p>Youtube: Deactivated</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if reindex %}
|
|
||||||
<p>Reindex scheduled</p>
|
|
||||||
{% else %}
|
|
||||||
<div id="reindex-button" class="button-box">
|
|
||||||
<button data-id="{{ video.youtube_id }}" data-type="video" onclick="reindex(this)" title="Reindex {{ video.title }}">Reindex</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<div class="button-box">
|
|
||||||
<a download="" href="/media/{{ video.media_url }}"><button id="download-item">Download File</button></a>
|
|
||||||
<button onclick="deleteConfirm()" id="delete-item">Delete Video</button>
|
|
||||||
<div class="delete-confirm" id="delete-button">
|
|
||||||
<span>Are you sure? </span><button class="danger-button" onclick="deleteVideo(this)" data-id="{{ video.youtube_id }}" data-redirect = "{{ video.channel.channel_id }}">Delete</button> <button onclick="cancelDelete()">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-box-item">
|
<div class="info-box-item">
|
||||||
|
@ -89,6 +75,34 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="info-box info-box-2">
|
||||||
|
<div class="info-box-item">
|
||||||
|
<div class="button-box">
|
||||||
|
{% if reindex %}
|
||||||
|
<p>Reindex scheduled</p>
|
||||||
|
{% else %}
|
||||||
|
<div id="reindex-button" class="button-box">
|
||||||
|
<button data-id="{{ video.youtube_id }}" data-type="video" onclick="reindex(this)" title="Reindex {{ video.title }}">Reindex</button>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<a download="" href="/media/{{ video.media_url }}"><button id="download-item">Download File</button></a>
|
||||||
|
<button onclick="deleteConfirm()" id="delete-item">Delete Video</button>
|
||||||
|
<div class="delete-confirm" id="delete-button">
|
||||||
|
<span>Are you sure? </span><button class="danger-button" onclick="deleteVideo(this)" data-id="{{ video.youtube_id }}" data-redirect = "{{ video.channel.channel_id }}">Delete</button> <button onclick="cancelDelete()">Cancel</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-box-item">
|
||||||
|
{% if video.media_size %}
|
||||||
|
<p>File size: {{ video.media_size|filesizeformat }}</p>
|
||||||
|
{% endif %}
|
||||||
|
{% if video.streams %}
|
||||||
|
{% for stream in video.streams %}
|
||||||
|
<p>{{ stream.type|title }}: {{ stream.codec }} {{ stream.bitrate|filesizeformat }}/s{% if stream.width %} <span class="space-carrot">|</span> {{ stream.width }}x{{ stream.height}}{% endif %}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% if video.tags %}
|
{% if video.tags %}
|
||||||
<div class="description-box">
|
<div class="description-box">
|
||||||
<div class="video-tag-box">
|
<div class="video-tag-box">
|
||||||
|
|
|
@ -660,6 +660,10 @@ video:-webkit-full-screen {
|
||||||
background-color: var(--highlight-bg);
|
background-color: var(--highlight-bg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.info-box-item p {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.description-text {
|
.description-text {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue