diff --git a/tubearchivist/home/config.json b/tubearchivist/home/config.json index 9ffe3769..3e5e941e 100644 --- a/tubearchivist/home/config.json +++ b/tubearchivist/home/config.json @@ -8,7 +8,8 @@ "home": "grid", "channel": "list", "downloads": "list", - "playlist": "grid" + "playlist": "grid", + "grid_items": 3 }, "subscriptions": { "auto_search": false, diff --git a/tubearchivist/home/src/download/queue.py b/tubearchivist/home/src/download/queue.py index 36e3d1e6..47225dd4 100644 --- a/tubearchivist/home/src/download/queue.py +++ b/tubearchivist/home/src/download/queue.py @@ -172,6 +172,8 @@ class PendingList(PendingIndex): """add video to list""" if url not in self.missing_videos and url not in self.to_skip: self.missing_videos.append(url) + else: + print(f"{url}: skipped adding already indexed video to download.") def _parse_channel(self, url): """add all videos of channel to list""" diff --git a/tubearchivist/home/src/download/subscriptions.py b/tubearchivist/home/src/download/subscriptions.py index 973c76e7..916c1707 100644 --- a/tubearchivist/home/src/download/subscriptions.py +++ b/tubearchivist/home/src/download/subscriptions.py @@ -43,7 +43,8 @@ class ChannelSubscription: if limit: obs["playlistend"] = self.config["subscriptions"]["channel_size"] - channel = YtWrap(obs, self.config).extract(channel_id) + url = f"https://www.youtube.com/channel/{channel_id}/videos" + channel = YtWrap(obs, self.config).extract(url) if not channel: return False diff --git a/tubearchivist/home/src/frontend/api_calls.py b/tubearchivist/home/src/frontend/api_calls.py index 8b0d9b3e..ed937aea 100644 --- a/tubearchivist/home/src/frontend/api_calls.py +++ b/tubearchivist/home/src/frontend/api_calls.py @@ -54,6 +54,7 @@ class PostData: "watched": self._watched, "un_watched": self._un_watched, "change_view": self._change_view, + "change_grid": self._change_grid, "rescan_pending": self._rescan_pending, "ignore": self._ignore, "dl_pending": self._dl_pending, @@ -100,6 +101,17 @@ class PostData: RedisArchivist().set_message(key, {"status": new_view}, expire=False) return {"success": True} + def _change_grid(self): + """process change items in grid""" + grid_items = int(self.exec_val) + grid_items = max(grid_items, 3) + grid_items = min(grid_items, 7) + + key = f"{self.current_user}:grid_items" + print(f"change grid items: {grid_items}") + RedisArchivist().set_message(key, {"status": grid_items}, expire=False) + return {"success": True} + @staticmethod def _rescan_pending(): """look for new items in subscribed channels""" diff --git a/tubearchivist/home/src/index/video.py b/tubearchivist/home/src/index/video.py index 7b951d86..fa2b0f96 100644 --- a/tubearchivist/home/src/index/video.py +++ b/tubearchivist/home/src/index/video.py @@ -12,6 +12,7 @@ import requests from django.conf import settings from home.src.es.connect import ElasticWrap from home.src.index import channel as ta_channel +from home.src.index import playlist as ta_playlist from home.src.index.generic import YouTubeItem from home.src.ta.helper import ( DurationConverter, @@ -189,9 +190,9 @@ class SubtitleParser: self.all_cues = [] for idx, event in enumerate(all_events): - if "dDurationMs" not in event: - # some events won't have a duration - print(f"failed to parse event without duration: {event}") + if "dDurationMs" not in event or "segs" not in event: + # some events won't have a duration or segs + print(f"skipping subtitle event without content: {event}") continue cue = { @@ -215,15 +216,16 @@ class SubtitleParser: if flatten: # fix overlapping retiming issue - if "dDurationMs" not in flatten[-1]: - # some events won't have a duration - print(f"failed to parse event without duration: {event}") + last = flatten[-1] + if "dDurationMs" not in last or "segs" not in last: + # some events won't have a duration or segs + print(f"skipping subtitle event without content: {event}") continue - last_end = flatten[-1]["tStartMs"] + flatten[-1]["dDurationMs"] + last_end = last["tStartMs"] + last["dDurationMs"] if event["tStartMs"] < last_end: - joined = flatten[-1]["segs"][0]["utf8"] + "\n" + text - flatten[-1]["segs"][0]["utf8"] = joined + joined = last["segs"][0]["utf8"] + "\n" + text + last["segs"][0]["utf8"] = joined continue event.update({"segs": [{"utf8": text}]}) @@ -560,6 +562,7 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle): def delete_media_file(self): """delete video file, meta data""" + print(f"{self.youtube_id}: delete video") self.get_from_es() video_base = self.app_conf["videos"] media_url = self.json_data.get("media_url") @@ -569,9 +572,28 @@ class YoutubeVideo(YouTubeItem, YoutubeSubtitle): except FileNotFoundError: print(f"{self.youtube_id}: failed {media_url}, continue.") + self.del_in_playlists() self.del_in_es() self.delete_subtitles() + def del_in_playlists(self): + """remove downloaded in playlist""" + all_playlists = self.json_data.get("playlist") + if not all_playlists: + return + + for playlist_id in all_playlists: + print(f"{playlist_id}: delete video {self.youtube_id}") + playlist = ta_playlist.YoutubePlaylist(playlist_id) + playlist.get_from_es() + entries = playlist.json_data["playlist_entries"] + for idx, entry in enumerate(entries): + if entry["youtube_id"] == self.youtube_id: + playlist.json_data["playlist_entries"][idx].update( + {"downloaded": False} + ) + playlist.upload_to_es() + def delete_subtitles(self): """delete indexed subtitles""" print(f"{self.youtube_id}: delete subtitles") diff --git a/tubearchivist/home/templates/home/channel_id.html b/tubearchivist/home/templates/home/channel_id.html index 8240132d..04a43336 100644 --- a/tubearchivist/home/templates/home/channel_id.html +++ b/tubearchivist/home/templates/home/channel_id.html @@ -112,6 +112,8 @@ {% endif %} + +