split playlist app

This commit is contained in:
Simon
2024-07-18 22:53:25 +02:00
parent 528bc5f2ef
commit 7af9ba364b
17 changed files with 170 additions and 155 deletions

View File

@@ -6,21 +6,6 @@ from django.urls import path
urlpatterns = [
path("ping/", views.PingView.as_view(), name="ping"),
path("login/", views.LoginApiView.as_view(), name="api-login"),
path(
"playlist/",
views.PlaylistApiListView.as_view(),
name="api-playlist-list",
),
path(
"playlist/<slug:playlist_id>/",
views.PlaylistApiView.as_view(),
name="api-playlist",
),
path(
"playlist/<slug:playlist_id>/video/",
views.PlaylistApiVideoView.as_view(),
name="api-playlist-video",
),
path(
"download/",
views.DownloadApiListView.as_view(),

View File

@@ -12,7 +12,6 @@ from api.src.aggs import (
from api.src.search_processor import SearchProcess
from home.models import CustomPeriodicTask
from home.src.download.queue import PendingInteract
from home.src.download.subscriptions import PlaylistSubscription
from home.src.download.yt_dlp_base import CookieHandler
from home.src.es.backup import ElasticBackup
from home.src.es.connect import ElasticWrap
@@ -20,7 +19,6 @@ from home.src.es.snapshot import ElasticSnapshot
from home.src.frontend.searching import SearchForm
from home.src.frontend.watched import WatchState
from home.src.index.generic import Pagination
from home.src.index.playlist import YoutubePlaylist
from home.src.index.reindex import ReindexProgress
from home.src.ta.config import AppConfig, ReleaseVersion
from home.src.ta.notify import Notifications, get_all_notifications
@@ -34,9 +32,8 @@ from home.tasks import (
download_pending,
extrac_dl,
run_restore_backup,
subscribe_to,
)
from rest_framework import permissions, status
from rest_framework import permissions
from rest_framework.authentication import (
SessionAuthentication,
TokenAuthentication,
@@ -132,135 +129,6 @@ class ApiBaseView(APIView):
self.response["paginate"] = self.pagination_handler.pagination
class PlaylistApiListView(ApiBaseView):
"""resolves to /api/playlist/
GET: returns list of indexed playlists
"""
search_base = "ta_playlist/_search/"
permission_classes = [AdminWriteOnly]
valid_playlist_type = ["regular", "custom"]
def get(self, request):
"""handle get request"""
playlist_type = request.GET.get("playlist_type", None)
query = {"sort": [{"playlist_name.keyword": {"order": "asc"}}]}
if playlist_type is not None:
if playlist_type not in self.valid_playlist_type:
message = f"invalid playlist_type {playlist_type}"
return Response({"message": message}, status=400)
query.update(
{
"query": {
"term": {"playlist_type": {"value": playlist_type}}
},
}
)
self.data.update(query)
self.get_document_list(request)
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):
"""resolves to /api/playlist/<playlist_id>/
GET: returns metadata dict of playlist
"""
search_base = "ta_playlist/_doc/"
permission_classes = [AdminWriteOnly]
valid_custom_actions = ["create", "remove", "up", "down", "top", "bottom"]
def get(self, request, playlist_id):
# pylint: disable=unused-argument
"""get request"""
self.get_document(playlist_id)
return Response(self.response, status=self.status_code)
def post(self, request, playlist_id):
"""post to custom playlist to add a video to list"""
playlist = YoutubePlaylist(playlist_id)
if not playlist.is_custom_playlist():
message = f"playlist with ID {playlist_id} is not custom"
return Response({"message": message}, status=400)
action = request.data.get("action")
if action not in self.valid_custom_actions:
message = f"invalid action: {action}"
return Response({"message": message}, status=400)
video_id = request.data.get("video_id")
if action == "create":
playlist.add_video_to_playlist(video_id)
else:
hide = UserConfig(request.user.id).get_value("hide_watched")
playlist.move_video(video_id, action, hide_watched=hide)
return Response({"success": True}, status=status.HTTP_201_CREATED)
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):
"""resolves to /api/playlist/<playlist_id>/video
GET: returns list of videos in playlist
"""
search_base = "ta_video/_search/"
def get(self, request, playlist_id):
"""handle get request"""
self.data["query"] = {
"term": {"playlist.keyword": {"value": playlist_id}}
}
self.data.update({"sort": [{"published": {"order": "desc"}}]})
self.get_document_list(request)
return Response(self.response, status=self.status_code)
class DownloadApiView(ApiBaseView):
"""resolves to /api/download/<video_id>/
GET: returns metadata dict of an item in the download queue

View File

@@ -12,8 +12,8 @@ from home.src.download.thumbnails import ThumbManager
from home.src.download.yt_dlp_base import YtWrap
from home.src.es.connect import ElasticWrap, IndexPaginate
from home.src.index.generic import YouTubeItem
from home.src.index.playlist import YoutubePlaylist
from home.src.ta.settings import EnvironmentSettings
from playlist.src.index import YoutubePlaylist
class YoutubeChannel(YouTubeItem):

View File

@@ -64,6 +64,7 @@ INSTALLED_APPS = [
"api",
"video",
"channel",
"playlist",
"config",
]

View File

@@ -22,5 +22,6 @@ urlpatterns = [
path("api/", include("api.urls")),
path("api/video/", include("video.urls")),
path("api/channel/", include("channel.urls")),
path("api/playlist/", include("playlist.urls")),
path("admin/", admin.site.urls),
]

View File

@@ -11,9 +11,9 @@ from home.src.download.subscriptions import ChannelSubscription
from home.src.download.thumbnails import ThumbManager
from home.src.download.yt_dlp_base import YtWrap
from home.src.es.connect import ElasticWrap, IndexPaginate
from home.src.index.playlist import YoutubePlaylist
from home.src.ta.config import AppConfig
from home.src.ta.helper import get_duration_str, is_shorts
from playlist.src.index import YoutubePlaylist
from video.src.constants import VideoTypeEnum

View File

@@ -8,10 +8,10 @@ from channel.src.index import YoutubeChannel
from home.src.download.thumbnails import ThumbManager
from home.src.download.yt_dlp_base import YtWrap
from home.src.es.connect import IndexPaginate
from home.src.index.playlist import YoutubePlaylist
from home.src.ta.config import AppConfig
from home.src.ta.helper import is_missing
from home.src.ta.urlparser import Parser
from playlist.src.index import YoutubePlaylist
from video.src.constants import VideoTypeEnum
from video.src.index import YoutubeVideo

View File

@@ -15,11 +15,11 @@ from home.src.download.queue import PendingList
from home.src.download.subscriptions import PlaylistSubscription
from home.src.download.yt_dlp_base import YtWrap
from home.src.es.connect import ElasticWrap, IndexPaginate
from home.src.index.playlist import YoutubePlaylist
from home.src.ta.config import AppConfig
from home.src.ta.helper import get_channel_overwrites, ignore_filelist
from home.src.ta.settings import EnvironmentSettings
from home.src.ta.ta_redis import RedisQueue
from playlist.src.index import YoutubePlaylist
from video.src.comments import CommentList
from video.src.constants import VideoTypeEnum
from video.src.index import YoutubeVideo, index_new_video

View File

@@ -16,10 +16,10 @@ from home.src.download.subscriptions import ChannelSubscription
from home.src.download.thumbnails import ThumbManager
from home.src.download.yt_dlp_base import CookieHandler
from home.src.es.connect import ElasticWrap, IndexPaginate
from home.src.index.playlist import YoutubePlaylist
from home.src.ta.config import AppConfig
from home.src.ta.settings import EnvironmentSettings
from home.src.ta.ta_redis import RedisQueue
from playlist.src.index import YoutubePlaylist
from video.src.comments import Comments
from video.src.index import YoutubeVideo

View File

@@ -42,7 +42,6 @@ from home.src.frontend.forms_schedule import (
SchedulerSettingsForm,
)
from home.src.index.generic import Pagination
from home.src.index.playlist import YoutubePlaylist
from home.src.index.reindex import ReindexProgress
from home.src.ta.config import AppConfig, ReleaseVersion
from home.src.ta.config_schedule import ScheduleBuilder
@@ -52,6 +51,7 @@ from home.src.ta.settings import EnvironmentSettings
from home.src.ta.ta_redis import RedisArchivist
from home.src.ta.users import UserConfig
from home.tasks import index_channel_playlists, subscribe_to
from playlist.src.index import YoutubePlaylist
from rest_framework.authtoken.models import Token
from video.src.constants import VideoTypeEnum

View File

View File

View File

@@ -0,0 +1,22 @@
"""all playlist API urls"""
from django.urls import path
from playlist import views
urlpatterns = [
path(
"",
views.PlaylistApiListView.as_view(),
name="api-playlist-list",
),
path(
"<slug:playlist_id>/",
views.PlaylistApiView.as_view(),
name="api-playlist",
),
path(
"<slug:playlist_id>/video/",
views.PlaylistApiVideoView.as_view(),
name="api-playlist-video",
),
]

View File

@@ -0,0 +1,138 @@
"""all playlist API views"""
from api.views import AdminWriteOnly, ApiBaseView
from home.src.download.subscriptions import PlaylistSubscription
from home.src.ta.users import UserConfig
from home.tasks import subscribe_to
from playlist.src.index import YoutubePlaylist
from rest_framework import status
from rest_framework.response import Response
class PlaylistApiListView(ApiBaseView):
"""resolves to /api/playlist/
GET: returns list of indexed playlists
"""
search_base = "ta_playlist/_search/"
permission_classes = [AdminWriteOnly]
valid_playlist_type = ["regular", "custom"]
def get(self, request):
"""handle get request"""
playlist_type = request.GET.get("playlist_type", None)
query = {"sort": [{"playlist_name.keyword": {"order": "asc"}}]}
if playlist_type is not None:
if playlist_type not in self.valid_playlist_type:
message = f"invalid playlist_type {playlist_type}"
return Response({"message": message}, status=400)
query.update(
{
"query": {
"term": {"playlist_type": {"value": playlist_type}}
},
}
)
self.data.update(query)
self.get_document_list(request)
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):
"""resolves to /api/playlist/<playlist_id>/
GET: returns metadata dict of playlist
"""
search_base = "ta_playlist/_doc/"
permission_classes = [AdminWriteOnly]
valid_custom_actions = ["create", "remove", "up", "down", "top", "bottom"]
def get(self, request, playlist_id):
# pylint: disable=unused-argument
"""get request"""
self.get_document(playlist_id)
return Response(self.response, status=self.status_code)
def post(self, request, playlist_id):
"""post to custom playlist to add a video to list"""
playlist = YoutubePlaylist(playlist_id)
if not playlist.is_custom_playlist():
message = f"playlist with ID {playlist_id} is not custom"
return Response({"message": message}, status=400)
action = request.data.get("action")
if action not in self.valid_custom_actions:
message = f"invalid action: {action}"
return Response({"message": message}, status=400)
video_id = request.data.get("video_id")
if action == "create":
playlist.add_video_to_playlist(video_id)
else:
hide = UserConfig(request.user.id).get_value("hide_watched")
playlist.move_video(video_id, action, hide_watched=hide)
return Response({"success": True}, status=status.HTTP_201_CREATED)
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):
"""resolves to /api/playlist/<playlist_id>/video
GET: returns list of videos in playlist
"""
search_base = "ta_video/_search/"
def get(self, request, playlist_id):
"""handle get request"""
self.data["query"] = {
"term": {"playlist.keyword": {"value": playlist_id}}
}
self.data.update({"sort": [{"published": {"order": "desc"}}]})
self.get_document_list(request)
return Response(self.response, status=self.status_code)

View File

@@ -11,11 +11,11 @@ import requests
from channel.src import index as ta_channel
from django.conf import settings
from home.src.es.connect import ElasticWrap
from home.src.index import playlist as ta_playlist
from home.src.index.generic import YouTubeItem
from home.src.ta.helper import get_duration_sec, get_duration_str, randomizor
from home.src.ta.settings import EnvironmentSettings
from home.src.ta.users import UserConfig
from playlist.src import index as ta_playlist
from ryd_client import ryd_client
from video.src.comments import Comments
from video.src.constants import VideoTypeEnum