mirror of
https://github.com/tubearchivist/tubearchivist
synced 2024-11-19 15:25:51 +00:00
API extensions, #build
Changed: - [API] Added endpoints for subscription toggle - [API] Added endpoint for playlist delete - Trigger bgsave when storing redis config - Validate subscribe url Type, surface errors - ignore eaDir folder
This commit is contained in:
commit
15794ebfc8
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
from api.src.search_processor import SearchProcess
|
from api.src.search_processor import SearchProcess
|
||||||
from home.src.download.queue import PendingInteract
|
from home.src.download.queue import PendingInteract
|
||||||
|
from home.src.download.subscriptions import (
|
||||||
|
ChannelSubscription,
|
||||||
|
PlaylistSubscription,
|
||||||
|
)
|
||||||
from home.src.download.yt_dlp_base import CookieHandler
|
from home.src.download.yt_dlp_base import CookieHandler
|
||||||
from home.src.es.connect import ElasticWrap
|
from home.src.es.connect import ElasticWrap
|
||||||
from home.src.es.snapshot import ElasticSnapshot
|
from home.src.es.snapshot import ElasticSnapshot
|
||||||
@ -9,6 +13,7 @@ from home.src.frontend.searching import SearchForm
|
|||||||
from home.src.frontend.watched import WatchState
|
from home.src.frontend.watched import WatchState
|
||||||
from home.src.index.channel import YoutubeChannel
|
from home.src.index.channel import YoutubeChannel
|
||||||
from home.src.index.generic import Pagination
|
from home.src.index.generic import Pagination
|
||||||
|
from home.src.index.playlist import YoutubePlaylist
|
||||||
from home.src.index.reindex import ReindexProgress
|
from home.src.index.reindex import ReindexProgress
|
||||||
from home.src.index.video import SponsorBlock, YoutubeVideo
|
from home.src.index.video import SponsorBlock, YoutubeVideo
|
||||||
from home.src.ta.config import AppConfig, ReleaseVersion
|
from home.src.ta.config import AppConfig, ReleaseVersion
|
||||||
@ -318,9 +323,8 @@ class ChannelApiListView(ApiBaseView):
|
|||||||
|
|
||||||
return Response(self.response)
|
return Response(self.response)
|
||||||
|
|
||||||
@staticmethod
|
def post(self, request):
|
||||||
def post(request):
|
"""subscribe/unsubscribe to list of channels"""
|
||||||
"""subscribe to list of channels"""
|
|
||||||
data = request.data
|
data = request.data
|
||||||
try:
|
try:
|
||||||
to_add = data["data"]
|
to_add = data["data"]
|
||||||
@ -329,12 +333,28 @@ class ChannelApiListView(ApiBaseView):
|
|||||||
print(message)
|
print(message)
|
||||||
return Response({"message": message}, status=400)
|
return Response({"message": message}, status=400)
|
||||||
|
|
||||||
pending = [i["channel_id"] for i in to_add if i["channel_subscribed"]]
|
pending = []
|
||||||
url_str = " ".join(pending)
|
for channel_item in to_add:
|
||||||
subscribe_to.delay(url_str)
|
channel_id = channel_item["channel_id"]
|
||||||
|
if channel_item["channel_subscribed"]:
|
||||||
|
pending.append(channel_id)
|
||||||
|
else:
|
||||||
|
self._unsubscribe(channel_id)
|
||||||
|
|
||||||
|
if pending:
|
||||||
|
url_str = " ".join(pending)
|
||||||
|
subscribe_to.delay(url_str, expected_type="channel")
|
||||||
|
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _unsubscribe(channel_id: str):
|
||||||
|
"""unsubscribe"""
|
||||||
|
print(f"[{channel_id}] unsubscribe from channel")
|
||||||
|
ChannelSubscription().change_subscribe(
|
||||||
|
channel_id, channel_subscribed=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChannelApiVideoView(ApiBaseView):
|
class ChannelApiVideoView(ApiBaseView):
|
||||||
"""resolves to /api/channel/<channel-id>/video
|
"""resolves to /api/channel/<channel-id>/video
|
||||||
@ -373,6 +393,38 @@ class PlaylistApiListView(ApiBaseView):
|
|||||||
self.get_document_list(request)
|
self.get_document_list(request)
|
||||||
return Response(self.response)
|
return Response(self.response)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
"""subscribe/unsubscribe to list of playlists"""
|
||||||
|
data = request.data
|
||||||
|
try:
|
||||||
|
to_add = data["data"]
|
||||||
|
except KeyError:
|
||||||
|
message = "missing expected data key"
|
||||||
|
print(message)
|
||||||
|
return Response({"message": message}, status=400)
|
||||||
|
|
||||||
|
pending = []
|
||||||
|
for playlist_item in to_add:
|
||||||
|
playlist_id = playlist_item["playlist_id"]
|
||||||
|
if playlist_item["playlist_subscribed"]:
|
||||||
|
pending.append(playlist_id)
|
||||||
|
else:
|
||||||
|
self._unsubscribe(playlist_id)
|
||||||
|
|
||||||
|
if pending:
|
||||||
|
url_str = " ".join(pending)
|
||||||
|
subscribe_to.delay(url_str, expected_type="playlist")
|
||||||
|
|
||||||
|
return Response(data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _unsubscribe(playlist_id: str):
|
||||||
|
"""unsubscribe"""
|
||||||
|
print(f"[{playlist_id}] unsubscribe from playlist")
|
||||||
|
PlaylistSubscription().change_subscribe(
|
||||||
|
playlist_id, subscribe_status=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PlaylistApiView(ApiBaseView):
|
class PlaylistApiView(ApiBaseView):
|
||||||
"""resolves to /api/playlist/<playlist_id>/
|
"""resolves to /api/playlist/<playlist_id>/
|
||||||
@ -387,6 +439,17 @@ class PlaylistApiView(ApiBaseView):
|
|||||||
self.get_document(playlist_id)
|
self.get_document(playlist_id)
|
||||||
return Response(self.response, status=self.status_code)
|
return Response(self.response, status=self.status_code)
|
||||||
|
|
||||||
|
def delete(self, request, playlist_id):
|
||||||
|
"""delete playlist"""
|
||||||
|
print(f"{playlist_id}: delete playlist")
|
||||||
|
delete_videos = request.GET.get("delete-videos", False)
|
||||||
|
if delete_videos:
|
||||||
|
YoutubePlaylist(playlist_id).delete_videos_playlist()
|
||||||
|
else:
|
||||||
|
YoutubePlaylist(playlist_id).delete_metadata()
|
||||||
|
|
||||||
|
return Response({"success": True})
|
||||||
|
|
||||||
|
|
||||||
class PlaylistApiVideoView(ApiBaseView):
|
class PlaylistApiVideoView(ApiBaseView):
|
||||||
"""resolves to /api/playlist/<playlist_id>/video
|
"""resolves to /api/playlist/<playlist_id>/video
|
||||||
|
@ -332,7 +332,7 @@ class SubscriptionHandler:
|
|||||||
self.task = task
|
self.task = task
|
||||||
self.to_subscribe = False
|
self.to_subscribe = False
|
||||||
|
|
||||||
def subscribe(self):
|
def subscribe(self, expected_type=False):
|
||||||
"""subscribe to url_str items"""
|
"""subscribe to url_str items"""
|
||||||
if self.task:
|
if self.task:
|
||||||
self.task.send_progress(["Processing form content."])
|
self.task.send_progress(["Processing form content."])
|
||||||
@ -343,11 +343,16 @@ class SubscriptionHandler:
|
|||||||
if self.task:
|
if self.task:
|
||||||
self._notify(idx, item, total)
|
self._notify(idx, item, total)
|
||||||
|
|
||||||
self.subscribe_type(item)
|
self.subscribe_type(item, expected_type=expected_type)
|
||||||
|
|
||||||
def subscribe_type(self, item):
|
def subscribe_type(self, item, expected_type):
|
||||||
"""process single item"""
|
"""process single item"""
|
||||||
if item["type"] == "playlist":
|
if item["type"] == "playlist":
|
||||||
|
if expected_type and expected_type != "playlist":
|
||||||
|
raise TypeError(
|
||||||
|
f"expected {expected_type} url but got {item.get('type')}"
|
||||||
|
)
|
||||||
|
|
||||||
PlaylistSubscription().process_url_str([item])
|
PlaylistSubscription().process_url_str([item])
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -360,6 +365,11 @@ class SubscriptionHandler:
|
|||||||
else:
|
else:
|
||||||
raise ValueError("failed to subscribe to: " + item["url"])
|
raise ValueError("failed to subscribe to: " + item["url"])
|
||||||
|
|
||||||
|
if expected_type and expected_type != "channel":
|
||||||
|
raise TypeError(
|
||||||
|
f"expected {expected_type} url but got {item.get('type')}"
|
||||||
|
)
|
||||||
|
|
||||||
self._subscribe(channel_id)
|
self._subscribe(channel_id)
|
||||||
|
|
||||||
def _subscribe(self, channel_id):
|
def _subscribe(self, channel_id):
|
||||||
|
@ -61,7 +61,7 @@ class ThumbManagerBase:
|
|||||||
print(f"{self.item_id}: retry thumbnail download {url}")
|
print(f"{self.item_id}: retry thumbnail download {url}")
|
||||||
sleep((i + 1) ** i)
|
sleep((i + 1) ** i)
|
||||||
|
|
||||||
return False
|
return self.get_fallback()
|
||||||
|
|
||||||
def get_fallback(self):
|
def get_fallback(self):
|
||||||
"""get fallback thumbnail if not available"""
|
"""get fallback thumbnail if not available"""
|
||||||
|
@ -112,9 +112,9 @@ class CookieHandler:
|
|||||||
|
|
||||||
def set_cookie(self, cookie):
|
def set_cookie(self, cookie):
|
||||||
"""set cookie str and activate in cofig"""
|
"""set cookie str and activate in cofig"""
|
||||||
RedisArchivist().set_message("cookie", cookie)
|
RedisArchivist().set_message("cookie", cookie, save=True)
|
||||||
path = ".downloads.cookie_import"
|
path = ".downloads.cookie_import"
|
||||||
RedisArchivist().set_message("config", True, path=path)
|
RedisArchivist().set_message("config", True, path=path, save=True)
|
||||||
self.config["downloads"]["cookie_import"] = True
|
self.config["downloads"]["cookie_import"] = True
|
||||||
print("cookie: activated and stored in Redis")
|
print("cookie: activated and stored in Redis")
|
||||||
|
|
||||||
|
@ -4,14 +4,8 @@ Functionality:
|
|||||||
- called via user input
|
- called via user input
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from home.src.download.subscriptions import (
|
|
||||||
ChannelSubscription,
|
|
||||||
PlaylistSubscription,
|
|
||||||
)
|
|
||||||
from home.src.index.playlist import YoutubePlaylist
|
|
||||||
from home.src.ta.ta_redis import RedisArchivist
|
from home.src.ta.ta_redis import RedisArchivist
|
||||||
from home.src.ta.urlparser import Parser
|
from home.tasks import run_restore_backup
|
||||||
from home.tasks import run_restore_backup, subscribe_to
|
|
||||||
|
|
||||||
|
|
||||||
class PostData:
|
class PostData:
|
||||||
@ -36,14 +30,11 @@ class PostData:
|
|||||||
exec_map = {
|
exec_map = {
|
||||||
"change_view": self._change_view,
|
"change_view": self._change_view,
|
||||||
"change_grid": self._change_grid,
|
"change_grid": self._change_grid,
|
||||||
"unsubscribe": self._unsubscribe,
|
|
||||||
"subscribe": self._subscribe,
|
|
||||||
"sort_order": self._sort_order,
|
"sort_order": self._sort_order,
|
||||||
"hide_watched": self._hide_watched,
|
"hide_watched": self._hide_watched,
|
||||||
"show_subed_only": self._show_subed_only,
|
"show_subed_only": self._show_subed_only,
|
||||||
"show_ignored_only": self._show_ignored_only,
|
"show_ignored_only": self._show_ignored_only,
|
||||||
"db-restore": self._db_restore,
|
"db-restore": self._db_restore,
|
||||||
"delete-playlist": self._delete_playlist,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return exec_map[self.to_exec]
|
return exec_map[self.to_exec]
|
||||||
@ -67,34 +58,6 @@ class PostData:
|
|||||||
RedisArchivist().set_message(key, {"status": grid_items})
|
RedisArchivist().set_message(key, {"status": grid_items})
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
|
|
||||||
def _unsubscribe(self):
|
|
||||||
"""unsubscribe from channels or playlists"""
|
|
||||||
id_unsub = self.exec_val
|
|
||||||
print(f"{id_unsub}: unsubscribe")
|
|
||||||
to_unsub_list = Parser(id_unsub).parse()
|
|
||||||
for to_unsub in to_unsub_list:
|
|
||||||
unsub_type = to_unsub["type"]
|
|
||||||
unsub_id = to_unsub["url"]
|
|
||||||
if unsub_type == "playlist":
|
|
||||||
PlaylistSubscription().change_subscribe(
|
|
||||||
unsub_id, subscribe_status=False
|
|
||||||
)
|
|
||||||
elif unsub_type == "channel":
|
|
||||||
ChannelSubscription().change_subscribe(
|
|
||||||
unsub_id, channel_subscribed=False
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError("failed to process " + id_unsub)
|
|
||||||
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
def _subscribe(self):
|
|
||||||
"""subscribe to channel or playlist, called from js buttons"""
|
|
||||||
id_sub = self.exec_val
|
|
||||||
print(f"{id_sub}: subscribe")
|
|
||||||
subscribe_to.delay(id_sub)
|
|
||||||
return {"success": True}
|
|
||||||
|
|
||||||
def _sort_order(self):
|
def _sort_order(self):
|
||||||
"""change the sort between published to downloaded"""
|
"""change the sort between published to downloaded"""
|
||||||
sort_order = {"status": self.exec_val}
|
sort_order = {"status": self.exec_val}
|
||||||
@ -139,16 +102,3 @@ class PostData:
|
|||||||
filename = self.exec_val
|
filename = self.exec_val
|
||||||
run_restore_backup.delay(filename)
|
run_restore_backup.delay(filename)
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
|
|
||||||
def _delete_playlist(self):
|
|
||||||
"""delete playlist, only metadata or incl all videos"""
|
|
||||||
playlist_dict = self.exec_val
|
|
||||||
playlist_id = playlist_dict["playlist-id"]
|
|
||||||
playlist_action = playlist_dict["playlist-action"]
|
|
||||||
print(f"{playlist_id}: delete playlist {playlist_action}")
|
|
||||||
if playlist_action == "metadata":
|
|
||||||
YoutubePlaylist(playlist_id).delete_metadata()
|
|
||||||
elif playlist_action == "all":
|
|
||||||
YoutubePlaylist(playlist_id).delete_videos_playlist()
|
|
||||||
|
|
||||||
return {"success": True}
|
|
||||||
|
@ -100,7 +100,7 @@ class AppConfig:
|
|||||||
self.config[config_dict][config_value] = to_write
|
self.config[config_dict][config_value] = to_write
|
||||||
updated.append((config_value, to_write))
|
updated.append((config_value, to_write))
|
||||||
|
|
||||||
RedisArchivist().set_message("config", self.config)
|
RedisArchivist().set_message("config", self.config, save=True)
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -112,7 +112,7 @@ class AppConfig:
|
|||||||
|
|
||||||
message = {"status": value}
|
message = {"status": value}
|
||||||
redis_key = f"{user_id}:{key}"
|
redis_key = f"{user_id}:{key}"
|
||||||
RedisArchivist().set_message(redis_key, message)
|
RedisArchivist().set_message(redis_key, message, save=True)
|
||||||
|
|
||||||
def get_colors(self):
|
def get_colors(self):
|
||||||
"""overwrite config if user has set custom values"""
|
"""overwrite config if user has set custom values"""
|
||||||
@ -225,7 +225,7 @@ class ScheduleBuilder:
|
|||||||
to_write = value
|
to_write = value
|
||||||
redis_config["scheduler"][key] = to_write
|
redis_config["scheduler"][key] = to_write
|
||||||
|
|
||||||
RedisArchivist().set_message("config", redis_config)
|
RedisArchivist().set_message("config", redis_config, save=True)
|
||||||
mess_dict = {
|
mess_dict = {
|
||||||
"status": self.MSG,
|
"status": self.MSG,
|
||||||
"level": "info",
|
"level": "info",
|
||||||
|
@ -15,7 +15,12 @@ import requests
|
|||||||
|
|
||||||
def ignore_filelist(filelist: list[str]) -> list[str]:
|
def ignore_filelist(filelist: list[str]) -> list[str]:
|
||||||
"""ignore temp files for os.listdir sanitizer"""
|
"""ignore temp files for os.listdir sanitizer"""
|
||||||
to_ignore = ["Icon\r\r", "Temporary Items", "Network Trash Folder"]
|
to_ignore = [
|
||||||
|
"@eaDir",
|
||||||
|
"Icon\r\r",
|
||||||
|
"Network Trash Folder",
|
||||||
|
"Temporary Items",
|
||||||
|
]
|
||||||
cleaned: list[str] = []
|
cleaned: list[str] = []
|
||||||
for file_name in filelist:
|
for file_name in filelist:
|
||||||
if file_name.startswith(".") or file_name in to_ignore:
|
if file_name.startswith(".") or file_name in to_ignore:
|
||||||
@ -110,7 +115,7 @@ def clear_dl_cache(config: dict) -> int:
|
|||||||
"""clear leftover files from dl cache"""
|
"""clear leftover files from dl cache"""
|
||||||
print("clear download cache")
|
print("clear download cache")
|
||||||
cache_dir = os.path.join(config["application"]["cache_dir"], "download")
|
cache_dir = os.path.join(config["application"]["cache_dir"], "download")
|
||||||
leftover_files = os.listdir(cache_dir)
|
leftover_files = ignore_filelist(os.listdir(cache_dir))
|
||||||
for cached in leftover_files:
|
for cached in leftover_files:
|
||||||
to_delete = os.path.join(cache_dir, cached)
|
to_delete = os.path.join(cache_dir, cached)
|
||||||
os.remove(to_delete)
|
os.remove(to_delete)
|
||||||
|
@ -41,6 +41,7 @@ class RedisArchivist(RedisBase):
|
|||||||
message: dict,
|
message: dict,
|
||||||
path: str = ".",
|
path: str = ".",
|
||||||
expire: bool | int = False,
|
expire: bool | int = False,
|
||||||
|
save: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""write new message to redis"""
|
"""write new message to redis"""
|
||||||
self.conn.execute_command(
|
self.conn.execute_command(
|
||||||
@ -54,6 +55,16 @@ class RedisArchivist(RedisBase):
|
|||||||
secs = expire
|
secs = expire
|
||||||
self.conn.execute_command("EXPIRE", self.NAME_SPACE + key, secs)
|
self.conn.execute_command("EXPIRE", self.NAME_SPACE + key, secs)
|
||||||
|
|
||||||
|
if save:
|
||||||
|
self.bg_save()
|
||||||
|
|
||||||
|
def bg_save(self) -> None:
|
||||||
|
"""save to aof"""
|
||||||
|
try:
|
||||||
|
self.conn.bgsave()
|
||||||
|
except redis.exceptions.ResponseError:
|
||||||
|
pass
|
||||||
|
|
||||||
def get_message(self, key: str) -> dict:
|
def get_message(self, key: str) -> dict:
|
||||||
"""get message dict from redis"""
|
"""get message dict from redis"""
|
||||||
reply = self.conn.execute_command("JSON.GET", self.NAME_SPACE + key)
|
reply = self.conn.execute_command("JSON.GET", self.NAME_SPACE + key)
|
||||||
|
@ -343,9 +343,12 @@ def re_sync_thumbs(self):
|
|||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True, name="subscribe_to", base=BaseTask)
|
@shared_task(bind=True, name="subscribe_to", base=BaseTask)
|
||||||
def subscribe_to(self, url_str):
|
def subscribe_to(self, url_str: str, expected_type: str | bool = False):
|
||||||
"""take a list of urls to subscribe to"""
|
"""
|
||||||
SubscriptionHandler(url_str, task=self).subscribe()
|
take a list of urls to subscribe to
|
||||||
|
optionally validate expected_type channel / playlist
|
||||||
|
"""
|
||||||
|
SubscriptionHandler(url_str, task=self).subscribe(expected_type)
|
||||||
|
|
||||||
|
|
||||||
@shared_task(bind=True, name="index_playlists", base=BaseTask)
|
@shared_task(bind=True, name="index_playlists", base=BaseTask)
|
||||||
|
@ -66,9 +66,9 @@
|
|||||||
<div>
|
<div>
|
||||||
<p>Last refreshed: {{ channel.source.channel_last_refresh }}</p>
|
<p>Last refreshed: {{ channel.source.channel_last_refresh }}</p>
|
||||||
{% if channel.source.channel_subscribed %}
|
{% if channel.source.channel_subscribed %}
|
||||||
<button class="unsubscribe" type="button" id="{{ channel.source.channel_id }}" onclick="unsubscribe(this.id)" title="Unsubscribe from {{ channel.source.channel_name }}">Unsubscribe</button>
|
<button class="unsubscribe" type="button" data-type="channel" data-subscribe="" data-id="{{ channel.source.channel_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ channel.source.channel_name }}">Unsubscribe</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" id="{{ channel.source.channel_id }}" onclick="subscribe(this.id)" title="Subscribe to {{ channel.source.channel_name }}">Subscribe</button>
|
<button type="button" data-type="channel" data-subscribe="true" data-id="{{ channel.source.channel_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ channel.source.channel_name }}">Subscribe</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -38,9 +38,9 @@
|
|||||||
<p>Subscribers: {{ channel_info.channel_subs|intcomma }}</p>
|
<p>Subscribers: {{ channel_info.channel_subs|intcomma }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if channel_info.channel_subscribed %}
|
{% if channel_info.channel_subscribed %}
|
||||||
<button class="unsubscribe" type="button" id="{{ channel_info.channel_id }}" onclick="unsubscribe(this.id)" title="Unsubscribe from {{ channel_info.channel_name }}">Unsubscribe</button>
|
<button class="unsubscribe" type="button" data-type="channel" data-subscribe="" data-id="{{ channel_info.channel_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ channel_info.channel_name }}">Unsubscribe</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" id="{{ channel_info.channel_id }}" onclick="subscribe(this.id)" title="Subscribe to {{ channel_info.channel_name }}">Subscribe</button>
|
<button type="button" data-type="channel" data-subscribe="true" data-id="{{ channel_info.channel_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ channel_info.channel_name }}">Subscribe</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,9 +54,9 @@
|
|||||||
<a href="{% url 'playlist_id' playlist.source.playlist_id %}"><h2>{{ playlist.source.playlist_name }}</h2></a>
|
<a href="{% url 'playlist_id' playlist.source.playlist_id %}"><h2>{{ playlist.source.playlist_name }}</h2></a>
|
||||||
<p>Last refreshed: {{ playlist.source.playlist_last_refresh }}</p>
|
<p>Last refreshed: {{ playlist.source.playlist_last_refresh }}</p>
|
||||||
{% if playlist.source.playlist_subscribed %}
|
{% if playlist.source.playlist_subscribed %}
|
||||||
<button class="unsubscribe" type="button" id="{{ playlist.source.playlist_id }}" onclick="unsubscribe(this.id)" title="Unsubscribe from {{ playlist.source.playlist_name }}">Unsubscribe</button>
|
<button class="unsubscribe" type="button" data-type="playlist" data-subscribe="" data-id="{{ playlist.source.playlist_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ playlist.source.playlist_name }}">Unsubscribe</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" id="{{ playlist.source.playlist_id }}" onclick="subscribe(this.id)" title="Subscribe to {{ playlist.source.playlist_name }}">Subscribe</button>
|
<button type="button" data-type="playlist" data-subscribe="true" data-id="{{ playlist.source.playlist_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ playlist.source.playlist_name }}">Subscribe</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,9 +49,9 @@
|
|||||||
<a href="{% url 'playlist_id' playlist.source.playlist_id %}"><h2>{{ playlist.source.playlist_name }}</h2></a>
|
<a href="{% url 'playlist_id' playlist.source.playlist_id %}"><h2>{{ playlist.source.playlist_name }}</h2></a>
|
||||||
<p>Last refreshed: {{ playlist.source.playlist_last_refresh }}</p>
|
<p>Last refreshed: {{ playlist.source.playlist_last_refresh }}</p>
|
||||||
{% if playlist.source.playlist_subscribed %}
|
{% if playlist.source.playlist_subscribed %}
|
||||||
<button class="unsubscribe" type="button" id="{{ playlist.source.playlist_id }}" onclick="unsubscribe(this.id)" title="Unsubscribe from {{ playlist.source.playlist_name }}">Unsubscribe</button>
|
<button class="unsubscribe" type="button" data-type="playlist" data-subscribe="" data-id="{{ playlist.source.playlist_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ playlist.source.playlist_name }}">Unsubscribe</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" id="{{ playlist.source.playlist_id }}" onclick="subscribe(this.id)" title="Subscribe to {{ playlist.source.playlist_name }}">Subscribe</button>
|
<button type="button" data-type="playlist" data-subscribe="true" data-id="{{ playlist.source.playlist_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ playlist.source.playlist_name }}">Subscribe</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -27,9 +27,9 @@
|
|||||||
<p>Last refreshed: {{ playlist_info.playlist_last_refresh }}</p>
|
<p>Last refreshed: {{ playlist_info.playlist_last_refresh }}</p>
|
||||||
<p>Playlist:
|
<p>Playlist:
|
||||||
{% if playlist_info.playlist_subscribed %}
|
{% if playlist_info.playlist_subscribed %}
|
||||||
<button class="unsubscribe" type="button" id="{{ playlist_info.playlist_id }}" onclick="unsubscribe(this.id)" title="Unsubscribe from {{ playlist_info.playlist_name }}">Unsubscribe</button>
|
<button class="unsubscribe" type="button" data-type="playlist" data-subscribe="" data-id="{{ playlist_info.playlist_id }}" onclick="subscribeStatus(this)" title="Unsubscribe from {{ playlist_info.playlist_name }}">Unsubscribe</button>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" id="{{ playlist_info.playlist_id }}" onclick="subscribe(this.id)" title="Subscribe to {{ playlist_info.playlist_name }}">Subscribe</button>
|
<button type="button" data-type="playlist" data-subscribe="true" data-id="{{ playlist_info.playlist_id }}" onclick="subscribeStatus(this)" title="Subscribe to {{ playlist_info.playlist_name }}">Subscribe</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% if playlist_info.playlist_active %}
|
{% if playlist_info.playlist_active %}
|
||||||
@ -40,8 +40,8 @@
|
|||||||
<button onclick="deleteConfirm()" id="delete-item">Delete Playlist</button>
|
<button onclick="deleteConfirm()" id="delete-item">Delete Playlist</button>
|
||||||
<div class="delete-confirm" id="delete-button">
|
<div class="delete-confirm" id="delete-button">
|
||||||
<span>Delete {{ playlist_info.playlist_name }}?</span>
|
<span>Delete {{ playlist_info.playlist_name }}?</span>
|
||||||
<button onclick="deletePlaylist(this)" data-action="metadata" data-id="{{ playlist_info.playlist_id }}">Delete metadata</button>
|
<button onclick="deletePlaylist(this)" data-action="" data-id="{{ playlist_info.playlist_id }}">Delete metadata</button>
|
||||||
<button onclick="deletePlaylist(this)" data-action="all" class="danger-button" data-id="{{ playlist_info.playlist_id }}">Delete all</button><br>
|
<button onclick="deletePlaylist(this)" data-action="delete-videos" class="danger-button" data-id="{{ playlist_info.playlist_id }}">Delete all</button><br>
|
||||||
<button onclick="cancelDelete()">Cancel</button>
|
<button onclick="cancelDelete()">Cancel</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -736,7 +736,7 @@ class ChannelView(ArchivistResultsView):
|
|||||||
if subscribe_form.is_valid():
|
if subscribe_form.is_valid():
|
||||||
url_str = request.POST.get("subscribe")
|
url_str = request.POST.get("subscribe")
|
||||||
print(url_str)
|
print(url_str)
|
||||||
subscribe_to.delay(url_str)
|
subscribe_to.delay(url_str, expected_type="channel")
|
||||||
|
|
||||||
sleep(1)
|
sleep(1)
|
||||||
return redirect("channel", permanent=True)
|
return redirect("channel", permanent=True)
|
||||||
@ -879,7 +879,7 @@ class PlaylistView(ArchivistResultsView):
|
|||||||
if subscribe_form.is_valid():
|
if subscribe_form.is_valid():
|
||||||
url_str = request.POST.get("subscribe")
|
url_str = request.POST.get("subscribe")
|
||||||
print(url_str)
|
print(url_str)
|
||||||
subscribe_to.delay(url_str)
|
subscribe_to.delay(url_str, expected_type="playlist")
|
||||||
|
|
||||||
sleep(1)
|
sleep(1)
|
||||||
return redirect("playlist")
|
return redirect("playlist")
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
apprise==1.4.5
|
apprise==1.4.5
|
||||||
celery==5.3.1
|
celery==5.3.1
|
||||||
Django==4.2.3
|
Django==4.2.4
|
||||||
django-auth-ldap==4.4.0
|
django-auth-ldap==4.5.0
|
||||||
django-cors-headers==4.2.0
|
django-cors-headers==4.2.0
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
Pillow==10.0.0
|
Pillow==10.0.0
|
||||||
redis==4.6.0
|
redis==5.0.0
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
ryd-client==0.0.6
|
ryd-client==0.0.6
|
||||||
uWSGI==2.0.21
|
uWSGI==2.0.22
|
||||||
whitenoise==6.5.0
|
whitenoise==6.5.0
|
||||||
yt_dlp==2023.7.6
|
yt_dlp==2023.7.6
|
||||||
|
@ -71,20 +71,27 @@ function isWatchedButton(button) {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unsubscribe(id_unsub) {
|
function subscribeStatus(subscribeButton) {
|
||||||
let payload = JSON.stringify({ unsubscribe: id_unsub });
|
let id = subscribeButton.getAttribute('data-id');
|
||||||
sendPost(payload);
|
let type = subscribeButton.getAttribute('data-type');
|
||||||
|
let subscribe = Boolean(subscribeButton.getAttribute('data-subscribe'));
|
||||||
|
let apiEndpoint;
|
||||||
|
let data;
|
||||||
|
if (type === 'channel') {
|
||||||
|
apiEndpoint = '/api/channel/';
|
||||||
|
data = { data: [{ channel_id: id, channel_subscribed: subscribe }] };
|
||||||
|
} else if (type === 'playlist') {
|
||||||
|
apiEndpoint = '/api/playlist/';
|
||||||
|
data = { data: [{ playlist_id: id, playlist_subscribed: subscribe }] };
|
||||||
|
}
|
||||||
|
apiRequest(apiEndpoint, 'POST', data);
|
||||||
let message = document.createElement('span');
|
let message = document.createElement('span');
|
||||||
message.innerText = 'You are unsubscribed.';
|
if (subscribe) {
|
||||||
document.getElementById(id_unsub).replaceWith(message);
|
message.innerText = 'You are subscribed.';
|
||||||
}
|
} else {
|
||||||
|
message.innerText = 'You are unsubscribed.';
|
||||||
function subscribe(id_sub) {
|
}
|
||||||
let payload = JSON.stringify({ subscribe: id_sub });
|
subscribeButton.replaceWith(message);
|
||||||
sendPost(payload);
|
|
||||||
let message = document.createElement('span');
|
|
||||||
message.innerText = 'You are subscribed.';
|
|
||||||
document.getElementById(id_sub).replaceWith(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeView(image) {
|
function changeView(image) {
|
||||||
@ -374,13 +381,11 @@ function deleteChannel(button) {
|
|||||||
function deletePlaylist(button) {
|
function deletePlaylist(button) {
|
||||||
let playlist_id = button.getAttribute('data-id');
|
let playlist_id = button.getAttribute('data-id');
|
||||||
let playlist_action = button.getAttribute('data-action');
|
let playlist_action = button.getAttribute('data-action');
|
||||||
let payload = JSON.stringify({
|
let apiEndpoint = `/api/playlist/${playlist_id}/`;
|
||||||
'delete-playlist': {
|
if (playlist_action === 'delete-videos') {
|
||||||
'playlist-id': playlist_id,
|
apiEndpoint += '?delete-videos=true';
|
||||||
'playlist-action': playlist_action,
|
}
|
||||||
},
|
apiRequest(apiEndpoint, 'DELETE');
|
||||||
});
|
|
||||||
sendPost(payload);
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
window.location.replace('/playlist/');
|
window.location.replace('/playlist/');
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@ -1057,9 +1062,9 @@ function createChannel(channel, viewStyle) {
|
|||||||
const channelLastRefresh = channel.channel_last_refresh;
|
const channelLastRefresh = channel.channel_last_refresh;
|
||||||
let button;
|
let button;
|
||||||
if (channel.channel_subscribed) {
|
if (channel.channel_subscribed) {
|
||||||
button = `<button class="unsubscribe" type="button" id="${channelId}" onclick="unsubscribe(this.id)" title="Unsubscribe from ${channelName}">Unsubscribe</button>`;
|
button = `<button class="unsubscribe" type="button" data-id="${channelId}" data-subscribe="" data-type="channel" onclick="subscribeStatus(this)" title="Unsubscribe from ${channelName}">Unsubscribe</button>`;
|
||||||
} else {
|
} else {
|
||||||
button = `<button type="button" id="${channelId}" onclick="subscribe(this.id)" title="Subscribe to ${channelName}">Subscribe</button>`;
|
button = `<button type="button" data-id="${channelId}" data-subscribe="true" data-type="channel" onclick="subscribeStatus(this)" title="Subscribe to ${channelName}">Subscribe</button>`;
|
||||||
}
|
}
|
||||||
// build markup
|
// build markup
|
||||||
const markup = `
|
const markup = `
|
||||||
@ -1103,9 +1108,9 @@ function createPlaylist(playlist, viewStyle) {
|
|||||||
const playlistLastRefresh = playlist.playlist_last_refresh;
|
const playlistLastRefresh = playlist.playlist_last_refresh;
|
||||||
let button;
|
let button;
|
||||||
if (playlist.playlist_subscribed) {
|
if (playlist.playlist_subscribed) {
|
||||||
button = `<button class="unsubscribe" type="button" id="${playlistId}" onclick="unsubscribe(this.id)" title="Unsubscribe from ${playlistName}">Unsubscribe</button>`;
|
button = `<button class="unsubscribe" type="button" data-id="${playlistId}" data-subscribe="" data-type="playlist" onclick="subscribeStatus(this)" title="Unsubscribe from ${playlistName}">Unsubscribe</button>`;
|
||||||
} else {
|
} else {
|
||||||
button = `<button type="button" id="${playlistId}" onclick="subscribe(this.id)" title="Subscribe to ${playlistName}">Subscribe</button>`;
|
button = `<button type="button" data-id="${playlistId}" data-subscribe="true" data-type="playlist" onclick="subscribeStatus(this)" title="Subscribe to ${playlistName}">Subscribe</button>`;
|
||||||
}
|
}
|
||||||
const markup = `
|
const markup = `
|
||||||
<div class="playlist-thumbnail">
|
<div class="playlist-thumbnail">
|
||||||
|
Loading…
Reference in New Issue
Block a user