mirror of
https://github.com/tubearchivist/tubearchivist.git
synced 2025-03-14 09:50:12 +00:00
implement video query building from url params
This commit is contained in:
parent
49f22bc43c
commit
f99e5c0081
@ -19,9 +19,4 @@ urlpatterns = [
|
|||||||
views.ChannelApiView.as_view(),
|
views.ChannelApiView.as_view(),
|
||||||
name="api-channel",
|
name="api-channel",
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
"<slug:channel_id>/video/",
|
|
||||||
views.ChannelApiVideoView.as_view(),
|
|
||||||
name="api-channel-video",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -129,25 +129,3 @@ class ChannelApiSearchView(ApiBaseView):
|
|||||||
self.get_document(parsed["url"])
|
self.get_document(parsed["url"])
|
||||||
|
|
||||||
return Response(self.response, status=self.status_code)
|
return Response(self.response, status=self.status_code)
|
||||||
|
|
||||||
|
|
||||||
class ChannelApiVideoView(ApiBaseView):
|
|
||||||
"""resolves to /api/channel/<channel-id>/video
|
|
||||||
GET: returns a list of videos of channel
|
|
||||||
"""
|
|
||||||
|
|
||||||
search_base = "ta_video/_search/"
|
|
||||||
|
|
||||||
def get(self, request, channel_id):
|
|
||||||
"""handle get request"""
|
|
||||||
self.data.update(
|
|
||||||
{
|
|
||||||
"query": {
|
|
||||||
"term": {"channel.channel_id": {"value": channel_id}}
|
|
||||||
},
|
|
||||||
"sort": [{"published": {"order": "desc"}}],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.get_document_list(request)
|
|
||||||
|
|
||||||
return Response(self.response, status=self.status_code)
|
|
||||||
|
@ -14,9 +14,4 @@ urlpatterns = [
|
|||||||
views.PlaylistApiView.as_view(),
|
views.PlaylistApiView.as_view(),
|
||||||
name="api-playlist",
|
name="api-playlist",
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
"<slug:playlist_id>/video/",
|
|
||||||
views.PlaylistApiVideoView.as_view(),
|
|
||||||
name="api-playlist-video",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -118,21 +118,3 @@ class PlaylistApiView(ApiBaseView):
|
|||||||
YoutubePlaylist(playlist_id).delete_metadata()
|
YoutubePlaylist(playlist_id).delete_metadata()
|
||||||
|
|
||||||
return Response({"success": True})
|
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)
|
|
||||||
|
@ -10,3 +10,21 @@ class VideoTypeEnum(enum.Enum):
|
|||||||
STREAMS = "streams"
|
STREAMS = "streams"
|
||||||
SHORTS = "shorts"
|
SHORTS = "shorts"
|
||||||
UNKNOWN = "unknown"
|
UNKNOWN = "unknown"
|
||||||
|
|
||||||
|
|
||||||
|
class SortEnum(enum.Enum):
|
||||||
|
"""all sort by options"""
|
||||||
|
|
||||||
|
PUBLISHED = "published"
|
||||||
|
DOWNLOADED = "date_downloaded"
|
||||||
|
VIEWS = "stats.view_count"
|
||||||
|
LIKES = "stats.like_count"
|
||||||
|
DURATION = "player.duration"
|
||||||
|
MEDIASIZE = "media_size"
|
||||||
|
|
||||||
|
|
||||||
|
class OrderEnum(enum.Enum):
|
||||||
|
"""all order by options"""
|
||||||
|
|
||||||
|
ASC = "asc"
|
||||||
|
DESC = "desc"
|
||||||
|
100
tubearchivist/video/src/query_building.py
Normal file
100
tubearchivist/video/src/query_building.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
"""build query for video fetching"""
|
||||||
|
|
||||||
|
from common.src.ta_redis import RedisArchivist
|
||||||
|
from video.src.constants import OrderEnum, SortEnum, VideoTypeEnum
|
||||||
|
|
||||||
|
|
||||||
|
class QueryBuilder:
|
||||||
|
"""contain functionality"""
|
||||||
|
|
||||||
|
WATCH_OPTIONS = ["watched", "unwatched", "continue"]
|
||||||
|
|
||||||
|
def __init__(self, user_id: int, **kwargs):
|
||||||
|
self.user_id = user_id
|
||||||
|
self.request_params = kwargs
|
||||||
|
|
||||||
|
def build_data(self) -> dict:
|
||||||
|
"""build data dict"""
|
||||||
|
data = {}
|
||||||
|
data["query"] = self.build_query()
|
||||||
|
if sort := self.parse_sort():
|
||||||
|
data["sort"] = sort
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
def build_query(self) -> dict:
|
||||||
|
"""build query key"""
|
||||||
|
must_list = []
|
||||||
|
channel = self.request_params.get("channel")
|
||||||
|
if channel:
|
||||||
|
must_list.append({"match": {"channel.channel_id": channel[0]}})
|
||||||
|
|
||||||
|
playlist = self.request_params.get("playlist")
|
||||||
|
if playlist:
|
||||||
|
must_list.append({"match": {"playlist.keyword": playlist[0]}})
|
||||||
|
|
||||||
|
watch = self.request_params.get("watch")
|
||||||
|
if watch:
|
||||||
|
watch_must_list = self._parse_watch(watch[0])
|
||||||
|
must_list.append(watch_must_list)
|
||||||
|
|
||||||
|
video_type = self.request_params.get("type")
|
||||||
|
if video_type:
|
||||||
|
type_list_list = self._parse_type(video_type[0])
|
||||||
|
must_list.append(type_list_list)
|
||||||
|
|
||||||
|
query = {"bool": {"must": must_list}}
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
||||||
|
def _parse_watch(self, watch: str) -> dict:
|
||||||
|
"""build query"""
|
||||||
|
if watch not in self.WATCH_OPTIONS:
|
||||||
|
raise ValueError(f"'{watch}' not in {self.WATCH_OPTIONS}")
|
||||||
|
|
||||||
|
if watch == "continue":
|
||||||
|
continue_must = self._build_continue_must()
|
||||||
|
return continue_must
|
||||||
|
|
||||||
|
return {"match": {"player.watched": watch == "watched"}}
|
||||||
|
|
||||||
|
def _build_continue_must(self):
|
||||||
|
results = RedisArchivist().list_items(f"{self.user_id}:progress:")
|
||||||
|
if not results:
|
||||||
|
return None
|
||||||
|
|
||||||
|
ids = [{"match": {"youtube_id": i.get("youtube_id")}} for i in results]
|
||||||
|
continue_ids = {"bool": {"should": ids}}
|
||||||
|
|
||||||
|
return continue_ids
|
||||||
|
|
||||||
|
def _parse_type(self, video_type: str):
|
||||||
|
"""parse video type"""
|
||||||
|
if not hasattr(VideoTypeEnum, video_type.upper()):
|
||||||
|
raise ValueError(f"'{video_type}' not in VideoTypeEnum")
|
||||||
|
|
||||||
|
vid_type = getattr(VideoTypeEnum, video_type.upper()).value
|
||||||
|
|
||||||
|
return {"match": {"vid_type": vid_type}}
|
||||||
|
|
||||||
|
def parse_sort(self) -> list | None:
|
||||||
|
"""build sort key"""
|
||||||
|
sort = self.request_params.get("sort")
|
||||||
|
if not sort:
|
||||||
|
return None
|
||||||
|
|
||||||
|
sort = sort[0]
|
||||||
|
if not hasattr(SortEnum, sort.upper()):
|
||||||
|
raise ValueError(f"'{sort}' not in SortEnum")
|
||||||
|
|
||||||
|
sort_field = getattr(SortEnum, sort.upper()).value
|
||||||
|
|
||||||
|
order = self.request_params.get("order", ["desc"])
|
||||||
|
order = order[0]
|
||||||
|
if not hasattr(OrderEnum, order.upper()):
|
||||||
|
raise ValueError(f"'{order}' not in OrderEnum")
|
||||||
|
|
||||||
|
order_by = getattr(OrderEnum, order.upper()).value
|
||||||
|
sort_key = [{sort_field: {"order": order_by}}]
|
||||||
|
|
||||||
|
return sort_key
|
@ -5,18 +5,31 @@ from common.views_base import AdminWriteOnly, ApiBaseView
|
|||||||
from playlist.src.index import YoutubePlaylist
|
from playlist.src.index import YoutubePlaylist
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from video.src.index import YoutubeVideo
|
from video.src.index import YoutubeVideo
|
||||||
|
from video.src.query_building import QueryBuilder
|
||||||
|
|
||||||
|
|
||||||
class VideoApiListView(ApiBaseView):
|
class VideoApiListView(ApiBaseView):
|
||||||
"""resolves to /api/video/
|
"""resolves to /api/video/
|
||||||
GET: returns list of videos
|
GET: returns list of videos
|
||||||
|
params:
|
||||||
|
- playlist:str=<playlist-id>
|
||||||
|
- channel:str=<channel-id>
|
||||||
|
- watch:enum=watched|unwatched|continue
|
||||||
|
- sort:enum=published|downloaded|views|likes|duration|filesize
|
||||||
|
- order:enum=asc|desc
|
||||||
|
- type:enum=videos|streams|shorts
|
||||||
"""
|
"""
|
||||||
|
|
||||||
search_base = "ta_video/_search/"
|
search_base = "ta_video/_search/"
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""get request"""
|
"""get request"""
|
||||||
self.data.update({"sort": [{"published": {"order": "desc"}}]})
|
try:
|
||||||
|
data = QueryBuilder(request.user.id, **request.GET).build_data()
|
||||||
|
except ValueError as err:
|
||||||
|
return Response({"error": str(err)}, status=400)
|
||||||
|
|
||||||
|
self.data = data
|
||||||
self.get_document_list(request)
|
self.get_document_list(request)
|
||||||
|
|
||||||
return Response(self.response)
|
return Response(self.response)
|
||||||
|
Loading…
Reference in New Issue
Block a user