mirror of
https://github.com/tubearchivist/tubearchivist-frontend.git
synced 2024-11-22 11:50:14 +00:00
Merge video progress bar to master
This commit is contained in:
commit
6822ed380d
@ -123,7 +123,7 @@ class VideoProgressView(ApiBaseView):
|
|||||||
"""set progress position in redis"""
|
"""set progress position in redis"""
|
||||||
position = request.data.get("position", 0)
|
position = request.data.get("position", 0)
|
||||||
key = f"{request.user.id}:progress:{video_id}"
|
key = f"{request.user.id}:progress:{video_id}"
|
||||||
message = {"position": position}
|
message = {"position": position, "youtube_id": video_id}
|
||||||
RedisArchivist().set_message(key, message, expire=False)
|
RedisArchivist().set_message(key, message, expire=False)
|
||||||
self.response = request.data
|
self.response = request.data
|
||||||
|
|
||||||
|
@ -48,7 +48,13 @@ class ChannelSubscription:
|
|||||||
}
|
}
|
||||||
if limit:
|
if limit:
|
||||||
obs["playlistend"] = self.channel_size
|
obs["playlistend"] = self.channel_size
|
||||||
|
|
||||||
|
try:
|
||||||
chan = yt_dlp.YoutubeDL(obs).extract_info(url, download=False)
|
chan = yt_dlp.YoutubeDL(obs).extract_info(url, download=False)
|
||||||
|
except yt_dlp.utils.DownloadError:
|
||||||
|
print(f"{channel_id}: failed to extract videos, skipping.")
|
||||||
|
return False
|
||||||
|
|
||||||
last_videos = [(i["id"], i["title"]) for i in chan["entries"]]
|
last_videos = [(i["id"], i["title"]) for i in chan["entries"]]
|
||||||
return last_videos
|
return last_videos
|
||||||
|
|
||||||
@ -66,6 +72,8 @@ class ChannelSubscription:
|
|||||||
for idx, channel in enumerate(all_channels):
|
for idx, channel in enumerate(all_channels):
|
||||||
channel_id = channel["channel_id"]
|
channel_id = channel["channel_id"]
|
||||||
last_videos = self.get_last_youtube_videos(channel_id)
|
last_videos = self.get_last_youtube_videos(channel_id)
|
||||||
|
|
||||||
|
if last_videos:
|
||||||
for video in last_videos:
|
for video in last_videos:
|
||||||
if video[0] not in to_ignore:
|
if video[0] not in to_ignore:
|
||||||
missing_videos.append(video[0])
|
missing_videos.append(video[0])
|
||||||
|
@ -59,6 +59,19 @@ class RedisArchivist:
|
|||||||
|
|
||||||
return json_str
|
return json_str
|
||||||
|
|
||||||
|
def list_items(self, query):
|
||||||
|
"""list all matches"""
|
||||||
|
reply = self.redis_connection.execute_command(
|
||||||
|
"KEYS", self.NAME_SPACE + query + "*"
|
||||||
|
)
|
||||||
|
all_matches = [i.decode().lstrip(self.NAME_SPACE) for i in reply]
|
||||||
|
all_results = []
|
||||||
|
for match in all_matches:
|
||||||
|
json_str = self.get_message(match)
|
||||||
|
all_results.append(json_str)
|
||||||
|
|
||||||
|
return all_results
|
||||||
|
|
||||||
def del_message(self, key):
|
def del_message(self, key):
|
||||||
"""delete key from redis"""
|
"""delete key from redis"""
|
||||||
response = self.redis_connection.execute_command(
|
response = self.redis_connection.execute_command(
|
||||||
|
@ -132,7 +132,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="boxed-content">
|
<div class="boxed-content">
|
||||||
<span>© 2021 - <script type="text/javascript">document.write(new Date().getFullYear());</script> TubeArchivist v0.1.1 </span><span><a href="{% url 'about' %}">About</a> | <a href="https://github.com/bbilly1/tubearchivist" target="_blank">GitHub</a> | <a href="https://hub.docker.com/r/bbilly1/tubearchivist" target="_blank">Docker Hub</a> | <a href="https://discord.gg/AFwz8nE7BK" target="_blank">Discord</a> | <a href="https://www.reddit.com/r/TubeArchivist/">Reddit</a></span>
|
<span>© 2021 - <script type="text/javascript">document.write(new Date().getFullYear());</script> TubeArchivist v0.1.2 </span><span><a href="{% url 'about' %}">About</a> | <a href="https://github.com/bbilly1/tubearchivist" target="_blank">GitHub</a> | <a href="https://hub.docker.com/r/bbilly1/tubearchivist" target="_blank">Docker Hub</a> | <a href="https://discord.gg/AFwz8nE7BK" target="_blank">Discord</a> | <a href="https://www.reddit.com/r/TubeArchivist/">Reddit</a></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
@ -110,6 +110,11 @@
|
|||||||
<div class="video-thumb-wrap {{ view_style }}">
|
<div class="video-thumb-wrap {{ view_style }}">
|
||||||
<div class="video-thumb">
|
<div class="video-thumb">
|
||||||
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
||||||
|
{% if video.source.player.progress %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: {{video.source.player.progress}}%;"></div>
|
||||||
|
{% else %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: 0%;"></div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="video-play">
|
<div class="video-play">
|
||||||
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
||||||
|
@ -49,6 +49,11 @@
|
|||||||
<div class="video-thumb-wrap {{ view_style }}">
|
<div class="video-thumb-wrap {{ view_style }}">
|
||||||
<div class="video-thumb">
|
<div class="video-thumb">
|
||||||
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
||||||
|
{% if video.source.player.progress %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: {{video.source.player.progress}}%;"></div>
|
||||||
|
{% else %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: 0%;"></div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="video-play">
|
<div class="video-play">
|
||||||
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
||||||
|
@ -91,6 +91,11 @@
|
|||||||
<div class="video-thumb-wrap {{ view_style }}">
|
<div class="video-thumb-wrap {{ view_style }}">
|
||||||
<div class="video-thumb">
|
<div class="video-thumb">
|
||||||
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
<img src="/cache/{{ video.source.vid_thumb_url }}" alt="video-thumb">
|
||||||
|
{% if video.source.player.progress %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: {{video.source.player.progress}}%;"></div>
|
||||||
|
{% else %}
|
||||||
|
<div class="video-progress-bar" id="progress-{{ video.source.youtube_id }}" style="width: 0%;"></div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="video-play">
|
<div class="video-play">
|
||||||
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
<img src="{% static 'img/icon-play.svg' %}" alt="play-icon">
|
||||||
|
@ -113,6 +113,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
window.onload = insertVideoTag('{{ video.youtube_id }}');
|
var videoData = getVideoData('{{ video.youtube_id }}');
|
||||||
|
var videoProgress = getVideoProgress('{{ video.youtube_id }}').position;
|
||||||
|
window.onload = insertVideoTag(videoData, videoProgress);
|
||||||
</script>
|
</script>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
@ -169,6 +169,20 @@ class ArchivistResultsView(ArchivistViewConfig):
|
|||||||
}
|
}
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
|
def match_progress(self):
|
||||||
|
"""add video progress to result context"""
|
||||||
|
results = RedisArchivist().list_items(f"{self.user_id}:progress:")
|
||||||
|
if not results or not self.context["results"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
progress = {i["youtube_id"]: i["position"] for i in results}
|
||||||
|
for hit in self.context["results"]:
|
||||||
|
video = hit["source"]
|
||||||
|
if video["youtube_id"] in progress:
|
||||||
|
played_sec = progress.get(video["youtube_id"])
|
||||||
|
total = video["player"]["duration"]
|
||||||
|
video["player"]["progress"] = 100 * (played_sec / total)
|
||||||
|
|
||||||
def single_lookup(self, es_path):
|
def single_lookup(self, es_path):
|
||||||
"""retrieve a single item from url"""
|
"""retrieve a single item from url"""
|
||||||
search = SearchHandler(es_path, config=self.default_conf)
|
search = SearchHandler(es_path, config=self.default_conf)
|
||||||
@ -212,6 +226,7 @@ class HomeView(ArchivistResultsView):
|
|||||||
self.initiate_vars(request)
|
self.initiate_vars(request)
|
||||||
self._update_view_data()
|
self._update_view_data()
|
||||||
self.find_results()
|
self.find_results()
|
||||||
|
self.match_progress()
|
||||||
|
|
||||||
return render(request, "home/home.html", self.context)
|
return render(request, "home/home.html", self.context)
|
||||||
|
|
||||||
@ -355,6 +370,7 @@ class ChannelIdView(ArchivistResultsView):
|
|||||||
self.initiate_vars(request)
|
self.initiate_vars(request)
|
||||||
self._update_view_data(channel_id)
|
self._update_view_data(channel_id)
|
||||||
self.find_results()
|
self.find_results()
|
||||||
|
self.match_progress()
|
||||||
|
|
||||||
if self.context["results"]:
|
if self.context["results"]:
|
||||||
channel_info = self.context["results"][0]["source"]["channel"]
|
channel_info = self.context["results"][0]["source"]["channel"]
|
||||||
@ -456,6 +472,7 @@ class PlaylistIdView(ArchivistResultsView):
|
|||||||
playlist_name = playlist_info["playlist_name"]
|
playlist_name = playlist_info["playlist_name"]
|
||||||
self._update_view_data(playlist_id, playlist_info)
|
self._update_view_data(playlist_id, playlist_info)
|
||||||
self.find_results()
|
self.find_results()
|
||||||
|
self.match_progress()
|
||||||
self.context.update(
|
self.context.update(
|
||||||
{
|
{
|
||||||
"title": "Playlist: " + playlist_name,
|
"title": "Playlist: " + playlist_name,
|
||||||
|
@ -43,6 +43,7 @@ function castVideoProgress(player) {
|
|||||||
var duration = player.duration;
|
var duration = player.duration;
|
||||||
if ((currentTime % 10) <= 1.0 && currentTime != 0 && duration != 0) { // Check progress every 10 seconds or else progress is checked a few times a second
|
if ((currentTime % 10) <= 1.0 && currentTime != 0 && duration != 0) { // Check progress every 10 seconds or else progress is checked a few times a second
|
||||||
postVideoProgress(videoId, currentTime);
|
postVideoProgress(videoId, currentTime);
|
||||||
|
setProgressBar(videoId, currentTime, duration);
|
||||||
if (!getVideoPlayerWatchStatus()) { // Check if video is already marked as watched
|
if (!getVideoPlayerWatchStatus()) { // Check if video is already marked as watched
|
||||||
if (watchedThreshold(currentTime, duration)) {
|
if (watchedThreshold(currentTime, duration)) {
|
||||||
isWatched(videoId);
|
isWatched(videoId);
|
||||||
|
@ -391,8 +391,17 @@ button:hover {
|
|||||||
grid-template-columns: 25% auto;
|
grid-template-columns: 25% auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-progress-bar {
|
||||||
|
position: absolute;
|
||||||
|
background-color: var(--accent-font-dark);
|
||||||
|
height: 7px;
|
||||||
|
left: 0;
|
||||||
|
bottom: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
.video-thumb img {
|
.video-thumb img {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-play img {
|
.video-play img {
|
||||||
|
@ -10,6 +10,7 @@ function sortChange(sortValue) {
|
|||||||
|
|
||||||
function isWatched(youtube_id) {
|
function isWatched(youtube_id) {
|
||||||
postVideoProgress(youtube_id, 0); // Reset video progress on watched;
|
postVideoProgress(youtube_id, 0); // Reset video progress on watched;
|
||||||
|
removeProgressBar(youtube_id);
|
||||||
var payload = JSON.stringify({'watched': youtube_id});
|
var payload = JSON.stringify({'watched': youtube_id});
|
||||||
sendPost(payload);
|
sendPost(payload);
|
||||||
var seenIcon = document.createElement('img');
|
var seenIcon = document.createElement('img');
|
||||||
@ -22,6 +23,11 @@ function isWatched(youtube_id) {
|
|||||||
document.getElementById(youtube_id).replaceWith(seenIcon);
|
document.getElementById(youtube_id).replaceWith(seenIcon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removes the progress bar when passed a video id
|
||||||
|
function removeProgressBar(videoId) {
|
||||||
|
setProgressBar(videoId, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
function isWatchedButton(button) {
|
function isWatchedButton(button) {
|
||||||
youtube_id = button.getAttribute("data-id");
|
youtube_id = button.getAttribute("data-id");
|
||||||
var payload = JSON.stringify({'watched': youtube_id});
|
var payload = JSON.stringify({'watched': youtube_id});
|
||||||
@ -298,9 +304,10 @@ function cancelDelete() {
|
|||||||
function createPlayer(button) {
|
function createPlayer(button) {
|
||||||
var videoId = button.getAttribute('data-id');
|
var videoId = button.getAttribute('data-id');
|
||||||
var videoData = getVideoData(videoId);
|
var videoData = getVideoData(videoId);
|
||||||
|
var videoProgress = getVideoProgress(videoId).position;
|
||||||
var videoName = videoData.data.title;
|
var videoName = videoData.data.title;
|
||||||
|
|
||||||
var videoTag = createVideoTag(videoId);
|
var videoTag = createVideoTag(videoData, videoProgress);
|
||||||
|
|
||||||
var playlist = '';
|
var playlist = '';
|
||||||
var videoPlaylists = videoData.data.playlist; // Array of playlists the video is in
|
var videoPlaylists = videoData.data.playlist; // Array of playlists the video is in
|
||||||
@ -369,19 +376,17 @@ function createPlayer(button) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add video tag to video page when passed a video id, function loaded on page load `video.html (115-117)`
|
// Add video tag to video page when passed a video id, function loaded on page load `video.html (115-117)`
|
||||||
function insertVideoTag(videoId) {
|
function insertVideoTag(videoData, videoProgress) {
|
||||||
var videoTag = createVideoTag(videoId);
|
var videoTag = createVideoTag(videoData, videoProgress);
|
||||||
var videoMain = document.getElementsByClassName("video-main");
|
var videoMain = document.getElementsByClassName("video-main");
|
||||||
videoMain[0].innerHTML = videoTag;
|
videoMain[0].innerHTML = videoTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a video tag with subtitles when passed a video id.
|
// Generates a video tag with subtitles when passed videoData and videoProgress.
|
||||||
function createVideoTag(videoId) {
|
function createVideoTag(videoData, videoProgress) {
|
||||||
var videoData = getVideoData(videoId);
|
var videoId = videoData.data.youtube_id;
|
||||||
var videoProgress = getVideoProgress(videoId).position;
|
|
||||||
var videoUrl = videoData.data.media_url;
|
var videoUrl = videoData.data.media_url;
|
||||||
var videoThumbUrl = videoData.data.vid_thumb_url;
|
var videoThumbUrl = videoData.data.vid_thumb_url;
|
||||||
|
|
||||||
var subtitles = '';
|
var subtitles = '';
|
||||||
var videoSubtitles = videoData.data.subtitles; // Array of subtitles
|
var videoSubtitles = videoData.data.subtitles; // Array of subtitles
|
||||||
if (typeof(videoSubtitles) != 'undefined' && videoData.config.downloads.subtitle) {
|
if (typeof(videoSubtitles) != 'undefined' && videoData.config.downloads.subtitle) {
|
||||||
@ -391,7 +396,7 @@ function createVideoTag(videoId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var videoTag = `
|
var videoTag = `
|
||||||
<video poster="${videoThumbUrl}" ontimeupdate="onVideoProgress()" onpause="onVideoPause()" controls autoplay width="100%" playsinline id="video-item">
|
<video poster="${videoThumbUrl}" ontimeupdate="onVideoProgress()" onpause="onVideoPause()" onended="onVideoEnded()" controls autoplay width="100%" playsinline id="video-item">
|
||||||
<source src="${videoUrl}#t=${videoProgress}" type="video/mp4" id="video-source" videoid="${videoId}">
|
<source src="${videoUrl}#t=${videoProgress}" type="video/mp4" id="video-source" videoid="${videoId}">
|
||||||
${subtitles}
|
${subtitles}
|
||||||
</video>
|
</video>
|
||||||
@ -460,6 +465,14 @@ function onVideoProgress() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs on video end, marks video as watched
|
||||||
|
function onVideoEnded() {
|
||||||
|
var videoId = getVideoPlayerVideoId();
|
||||||
|
if (!getVideoPlayerWatchStatus()) { // Check if video is already marked as watched
|
||||||
|
isWatched(videoId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function watchedThreshold(currentTime, duration) {
|
function watchedThreshold(currentTime, duration) {
|
||||||
var watched = false;
|
var watched = false;
|
||||||
if (duration <= 1800){ // If video is less than 30 min
|
if (duration <= 1800){ // If video is less than 30 min
|
||||||
@ -538,16 +551,17 @@ function getSubbedPlaylists(videoPlaylists) {
|
|||||||
// Send video position when given video id and progress in seconds
|
// Send video position when given video id and progress in seconds
|
||||||
function postVideoProgress(videoId, videoProgress) {
|
function postVideoProgress(videoId, videoProgress) {
|
||||||
var apiEndpoint = "/api/video/" + videoId + "/progress/";
|
var apiEndpoint = "/api/video/" + videoId + "/progress/";
|
||||||
if (!isNaN(videoProgress)) {
|
var duartion = getVideoPlayerDuration();
|
||||||
|
if (!isNaN(videoProgress) && duartion != 'undefined') {
|
||||||
var data = {
|
var data = {
|
||||||
"position": videoProgress
|
"position": videoProgress
|
||||||
};
|
};
|
||||||
if (videoProgress == 0) {
|
if (videoProgress == 0) {
|
||||||
apiRequest(apiEndpoint, "DELETE");
|
apiRequest(apiEndpoint, "DELETE");
|
||||||
console.log("Deleting Video Progress for Video ID: " + videoId + ", Progress: " + videoProgress);
|
// console.log("Deleting Video Progress for Video ID: " + videoId + ", Progress: " + videoProgress);
|
||||||
} else if (!getVideoPlayerWatchStatus()) {
|
} else if (!getVideoPlayerWatchStatus()) {
|
||||||
apiRequest(apiEndpoint, "POST", data);
|
apiRequest(apiEndpoint, "POST", data);
|
||||||
console.log("Saving Video Progress for Video ID: " + videoId + ", Progress: " + videoProgress);
|
// console.log("Saving Video Progress for Video ID: " + videoId + ", Progress: " + videoProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -564,14 +578,17 @@ function apiRequest(apiEndpoint, method, data) {
|
|||||||
return JSON.parse(xhttp.responseText);
|
return JSON.parse(xhttp.responseText);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gets origin URL
|
||||||
function getURL() {
|
function getURL() {
|
||||||
return window.location.href.replace(window.location.pathname, "");
|
return window.location.origin;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePlayer() {
|
function removePlayer() {
|
||||||
var currentTime = getVideoPlayerCurrentTime();
|
var currentTime = getVideoPlayerCurrentTime();
|
||||||
|
var duration = getVideoPlayerDuration();
|
||||||
var videoId = getVideoPlayerVideoId();
|
var videoId = getVideoPlayerVideoId();
|
||||||
postVideoProgress(videoId, currentTime);
|
postVideoProgress(videoId, currentTime);
|
||||||
|
setProgressBar(videoId, currentTime, duration);
|
||||||
var playerElement = document.getElementById('player');
|
var playerElement = document.getElementById('player');
|
||||||
if (playerElement.hasChildNodes()) {
|
if (playerElement.hasChildNodes()) {
|
||||||
var youtubeId = playerElement.childNodes[1].getAttribute("data-id");
|
var youtubeId = playerElement.childNodes[1].getAttribute("data-id");
|
||||||
@ -587,6 +604,14 @@ function removePlayer() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sets the progress bar when passed a video id, video progress and video duration
|
||||||
|
function setProgressBar(videoId, currentTime, duration) {
|
||||||
|
progressBar = document.getElementById("progress-" + videoId);
|
||||||
|
progressBarWidth = (currentTime / duration) * 100 + "%";
|
||||||
|
if (progressBar) {
|
||||||
|
progressBar.style.width = progressBarWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// multi search form
|
// multi search form
|
||||||
function searchMulti(query) {
|
function searchMulti(query) {
|
||||||
|
Loading…
Reference in New Issue
Block a user