rcdl 3.0.0b13__py3-none-any.whl → 3.0.0b23__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ from rcdl.interface.ui import UI, NestedProgress
14
14
  from rcdl.core import parser
15
15
  from rcdl.core.models import Media, Post
16
16
  from rcdl.core.config import Config
17
+ from rcdl.utils import bytes_to_str
17
18
 
18
19
 
19
20
  def ytdlp_clear_cache():
@@ -338,7 +339,10 @@ def handbrake_optimized(media: Media, user: str, progress: NestedProgress):
338
339
 
339
340
  assert process.stdout is not None
340
341
  progress.start_current(description="Optimizing", total=100)
341
- progress.set_status(f"user@({media.service}) ->", f"{media.file_size}")
342
+ progress.set_status(
343
+ f"{user}@({media.service}) -> ",
344
+ f"{media.file_path} ({bytes_to_str(media.file_size)})",
345
+ )
342
346
 
343
347
  current_progress = 0.0
344
348
 
rcdl/gui/video_manager.py CHANGED
@@ -28,62 +28,72 @@ def set_status(media: Media, status: Status):
28
28
 
29
29
 
30
30
  def video_manager():
31
+ if "reload_medias" not in st.session_state:
32
+ st.session_state.reload_medias = True
33
+
31
34
  st.title("Video Manager")
32
35
 
33
36
  # Filter & Sorting UI
34
37
  with st.expander("Filters & Sorting", expanded=True):
35
38
  col1, col2, col3 = st.columns(3)
36
39
  with col1:
37
- sort_by = st.selectbox(
40
+ st.selectbox(
38
41
  "Sort By",
39
42
  options=["file_size", "service", "duration", "file_path"],
40
43
  index=0,
44
+ key="sort_by",
41
45
  )
42
46
  with col2:
43
- ascending = st.radio(
47
+ st.radio(
44
48
  "Order",
45
49
  options=[True, False],
46
50
  format_func=lambda x: "Ascending" if x else "Descending",
47
51
  horizontal=True,
52
+ key="ascending",
48
53
  )
49
54
  with col3:
50
- creator_filter = st.text_input(
51
- "Creator ID(user)", placeholder="Leave empty for all"
55
+ st.text_input(
56
+ "Creator ID(user)",
57
+ placeholder="Leave empty for all",
58
+ key="creator_filter",
52
59
  )
53
- status_filter = st.multiselect(
60
+ st.multiselect(
54
61
  "Status",
55
62
  options=list(Status),
56
63
  default=[Status.DOWNLOADED, Status.OPTIMIZED],
64
+ key="status_filter",
57
65
  )
58
66
 
59
- reload = st.button("Apply")
67
+ if st.button("Apply"):
68
+ st.session_state.reload_medias = True
60
69
 
61
70
  # load db
62
- if reload or "medias" not in st.session_state:
71
+ if st.session_state.reload_medias or "medias" not in st.session_state:
63
72
  with DB() as db:
64
73
  medias = db.query_medias_by_status_sorted(
65
- status_filter,
66
- sort_by=sort_by,
67
- ascending=ascending,
74
+ st.session_state.status_filter,
75
+ sort_by=st.session_state.sort_by,
76
+ ascending=st.session_state.ascending,
68
77
  )
69
78
 
70
79
  # check if in a fuse group
71
80
 
72
81
  # creator filter
73
- if creator_filter:
82
+ if st.session_state.creator_filter:
74
83
  filtered = []
75
84
  for m in medias:
76
85
  post = db.query_post_by_id(m.post_id)
77
- if post and post.user == creator_filter:
78
- filtered.append(m)
79
- # check i na fuse group
80
- fm = db.query_fuses_by_id(m.post_id)
81
- if fm is None:
86
+ if (
87
+ post
88
+ and post.user == st.session_state.creator_filter
89
+ and db.query_fuses_by_id(m.post_id) is None
90
+ ):
82
91
  filtered.append(m)
83
92
  medias = filtered
84
93
 
85
94
  st.session_state.medias = medias
86
95
  st.session_state.media_index = 0
96
+ st.session_state.reload_medias = False
87
97
 
88
98
  medias = st.session_state.medias
89
99
  if not medias:
@@ -157,14 +167,12 @@ def video_manager():
157
167
  st.rerun()
158
168
 
159
169
  # video player
160
- full_path = os.path.join(Config.creator_folder(post.user), media.file_path)
161
- if os.path.exists(full_path):
162
- with col_video:
163
- with st.container():
164
- if media.file_size > 199 * 1024 * 1024: # 199MB
165
- with open(full_path, "rb") as f:
166
- st.video(f.read(), autoplay=True, loop=True)
167
- else:
168
- st.video(full_path, autoplay=True, loop=True)
169
- else:
170
- st.error(f"Video file {full_path} not found on disk")
170
+ with col_video:
171
+ full_path = os.path.join(Config.creator_folder(post.user), media.file_path)
172
+ video_slot = st.empty()
173
+ video_slot.empty()
174
+
175
+ if os.path.exists(full_path):
176
+ video_slot.video(full_path, autoplay=False, loop=False)
177
+ else:
178
+ st.error(f"Video file {full_path} not found on disk")
rcdl/interface/ui.py CHANGED
@@ -28,6 +28,7 @@ class NestedProgress:
28
28
  self.total_task: int | None = None
29
29
  self.current_task: int | None = None
30
30
  self.status_text = Text("", style="cyan")
31
+ self.current_label = ""
31
32
 
32
33
  def start(
33
34
  self, *, total: int, total_label: str = "Total", current_label: str = "Current"
@@ -54,6 +55,7 @@ class NestedProgress:
54
55
  transient=False,
55
56
  )
56
57
 
58
+ self.current_label = current_label
57
59
  group = Group(self.global_progress, self.current_progress, self.status_text)
58
60
  self.live = Live(group, console=self.console)
59
61
  self.live.__enter__()
@@ -68,14 +70,28 @@ class NestedProgress:
68
70
  if self.global_progress and self.total_task is not None:
69
71
  self.global_progress.advance(self.total_task, step) # type: ignore
70
72
 
73
+ def reset_current(self):
74
+ if not self.current_progress or self.current_task is None:
75
+ return
76
+
77
+ self.current_progress.remove_task(self.current_task) # type: ignore
78
+
79
+ self.current_task = self.current_progress.add_task(
80
+ self.current_label,
81
+ total=1,
82
+ visible=False,
83
+ )
84
+
71
85
  def start_current(self, description: str, total: int | None = None):
72
86
  if not self.current_progress or self.current_task is None:
73
87
  return
74
88
 
89
+ self.reset_current()
90
+
75
91
  self.current_progress.update(
76
92
  self.current_task, # type: ignore
77
93
  description=description,
78
- total=total,
94
+ total=total or 1,
79
95
  completed=0,
80
96
  visible=True,
81
97
  )
@@ -88,18 +104,14 @@ class NestedProgress:
88
104
  if self.current_progress and self.current_task is not None:
89
105
  self.current_progress.update(self.current_task, visible=False) # type: ignore
90
106
 
91
- # ---------------------
92
107
  # Status line
93
- # ---------------------
94
108
  def set_status(self, cyan: str, green: str = ""):
95
109
  self.status_text.plain = ""
96
110
  self.status_text.append(cyan, style="cyan")
97
111
  if green:
98
112
  self.status_text.append(green, style="green")
99
113
 
100
- # ---------------------
101
114
  # Close
102
- # ---------------------
103
115
  def close(self):
104
116
  if self.live:
105
117
  self.live.__exit__(None, None, None)
rcdl/utils.py CHANGED
@@ -9,7 +9,6 @@ from pathlib import Path
9
9
  import os
10
10
  import time
11
11
 
12
- import rcdl.core.downloader_subprocess as dls
13
12
  from rcdl.core.config import Config
14
13
  from rcdl.interface.ui import UI
15
14
 
@@ -21,6 +20,8 @@ def get_date_now() -> str:
21
20
 
22
21
  def get_media_metadata(full_path: str) -> tuple[int, int, str]:
23
22
  """Get duration (if possible), file_size and checksum"""
23
+ from rcdl.core.downloader_subprocess import ffprobe_get_duration
24
+
24
25
  path = Path(full_path)
25
26
  if not os.path.exists(path):
26
27
  UI.error(f"{path} path should exist but does not.")
@@ -29,7 +30,7 @@ def get_media_metadata(full_path: str) -> tuple[int, int, str]:
29
30
  checksum = get_media_hash(path)
30
31
  if checksum is None:
31
32
  checksum = ""
32
- duration = dls.ffprobe_get_duration(path)
33
+ duration = ffprobe_get_duration(path)
33
34
  if duration is None:
34
35
  duration = 0
35
36
  return duration, file_size, checksum
@@ -66,8 +67,17 @@ def get_json_hash(data: dict) -> tuple[str, str]:
66
67
  return raw_json, json_hash
67
68
 
68
69
 
69
- def bytes_to_mb(bytes: float | int):
70
- return round(bytes / (1024 * 1024), 1)
70
+ def bytes_to_mb(bytes: float | int) -> float:
71
+ return bytes / (1024 * 1024)
72
+
73
+
74
+ def bytes_to_str(bytes: float | int) -> str:
75
+ mb = bytes_to_mb(bytes)
76
+
77
+ if mb > 1024:
78
+ gb = mb / 1024
79
+ return f"{gb:.1f} GB"
80
+ return f"{mb:.1f} MB"
71
81
 
72
82
 
73
83
  def clean_all(all: bool, partial: bool, cache: bool, medias_deleted: bool):
@@ -75,6 +85,7 @@ def clean_all(all: bool, partial: bool, cache: bool, medias_deleted: bool):
75
85
 
76
86
  from rcdl.core.db import DB
77
87
  from rcdl.core.models import Status
88
+ from rcdl.core.downloader_subprocess import ytdlp_clear_cache, kill_aria2c
78
89
 
79
90
  if all:
80
91
  partial = True
@@ -106,11 +117,11 @@ def clean_all(all: bool, partial: bool, cache: bool, medias_deleted: bool):
106
117
  # cache
107
118
  if cache:
108
119
  # clear yt-dlp cache
109
- dls.ytdlp_clear_cache()
120
+ ytdlp_clear_cache()
110
121
  UI.info("Cleared yt-dlp cache dir")
111
122
 
112
123
  # kill aria2c
113
- dls.kill_aria2c()
124
+ kill_aria2c()
114
125
  UI.info("Kill aria2c")
115
126
 
116
127
  # medias with status deleted
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rcdl
3
- Version: 3.0.0b13
3
+ Version: 3.0.0b23
4
4
  Summary: Coomer/Kemono CLI Downloader
5
5
  Keywords: downloader,video,media
6
6
  Author: Anonymous
@@ -1,6 +1,6 @@
1
1
  rcdl/__init__.py,sha256=MIsNipkMNzSOT2WkNbSmVLvo3sdPBPN0xCOMP2r5z50,175
2
2
  rcdl/__main__.py,sha256=ge7lh3rCaWuUgVpwU88zyQGPtZgG7GLW4rslT9wo9j8,714
3
- rcdl/utils.py,sha256=hcaQExh8CuLgpYjDx4qBzLFjV9flnZIQsEpE1Z8Apb8,5016
3
+ rcdl/utils.py,sha256=3WiJhtdafyEDYR4fYUBoqH6sVdSHbjghkROeJby8ScQ,5279
4
4
  rcdl/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  rcdl/core/adapters.py,sha256=I__3dvSwI2W8ZZfao9RNzdyLivGBOVDk_zfx39KIuHc,7258
6
6
  rcdl/core/api.py,sha256=2OAUQV89mq1ELo9Ydj9zCde5qGHgI7bom8XLSeq7Ok8,2342
@@ -8,7 +8,7 @@ rcdl/core/config.py,sha256=9b5HTKLpBWShXqpTbgQUq3xdCqDQUs466nI16fRiWEk,6315
8
8
  rcdl/core/db.py,sha256=Ab6SuC093fQvJybbzYHvhYEkCdGW-BheUrpZhM-6j1A,9302
9
9
  rcdl/core/db_queries.py,sha256=KZW3SotPZamDxPY1KcCxo9-GvgnW6vjxDFu4h3HI1m8,2225
10
10
  rcdl/core/downloader.py,sha256=UyMz_c-kHmmASIhd8Co3khHuaTYOUTRpizp1zr-BHjY,10329
11
- rcdl/core/downloader_subprocess.py,sha256=jva51d_gONsSoQFzJeGO9kEc3aOWJFEH7C7vCDrnxYc,10279
11
+ rcdl/core/downloader_subprocess.py,sha256=w9WPH2pOTFv-4dEp_iklN1bZLydGd3MjTfhiQEkp7Es,10375
12
12
  rcdl/core/file_io.py,sha256=C-W9GLQReGiuWKTLzVTsisI_ps5j0SeqNQM9VjJot14,1040
13
13
  rcdl/core/fuse.py,sha256=OKeWHh-WXWicLeCq_jgqKQovdDPfKAk2fi8lgUV-FKw,4188
14
14
  rcdl/core/models.py,sha256=1aMwEupTk68PfHrbY1v6il9p-cmMIMcdFk6Aqp9yU8M,1910
@@ -18,11 +18,11 @@ rcdl/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
18
  rcdl/gui/__main__.py,sha256=Ti5dQqYxcyHuAOT8FGjYMhV0Y-j9Y-6utRkV7eRmyWA,68
19
19
  rcdl/gui/db_viewer.py,sha256=0fM673d2JnWknFqVUDtDhzN6ojP1SGG06pO7T46IOHo,1060
20
20
  rcdl/gui/gui.py,sha256=38mn30ZQPNN0lTyqh5AwIuszkNQ_SdE_FdRzkZXSEVE,1054
21
- rcdl/gui/video_manager.py,sha256=ShOKmlw44ybZcO4E8UamaWAKHY5uQgj3LUHKy_7tKI8,5656
21
+ rcdl/gui/video_manager.py,sha256=nVravn1WAko5HP6gC03-v4kJKYZVUOIt5uOvs4PCOkU,5842
22
22
  rcdl/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
23
  rcdl/interface/cli.py,sha256=mAKvphCoEXWtcnJfD5lsBGU5ooOKJM-G_Y4SeV9aUos,6094
24
- rcdl/interface/ui.py,sha256=XXip0RiAjGC7yGbU_fctxGOp_TiFKSvHzA2zpUMwdsc,5735
25
- rcdl-3.0.0b13.dist-info/entry_points.txt,sha256=TSFT1avCCO1d8pJnvuQLzX_1bA96uIDV_alKuruDN4E,42
26
- rcdl-3.0.0b13.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
27
- rcdl-3.0.0b13.dist-info/METADATA,sha256=NCpTE5iScpVYyf4Zl6e0EQDCKvn0kMAvZ08KajYC-E8,2945
28
- rcdl-3.0.0b13.dist-info/RECORD,,
24
+ rcdl/interface/ui.py,sha256=hR0JQME9ZER_GakFpi0OhK-7WB3wdx0U2KkRqkcGTkc,6078
25
+ rcdl-3.0.0b23.dist-info/entry_points.txt,sha256=TSFT1avCCO1d8pJnvuQLzX_1bA96uIDV_alKuruDN4E,42
26
+ rcdl-3.0.0b23.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
27
+ rcdl-3.0.0b23.dist-info/METADATA,sha256=m_FH-E7_pzu1h8AAWOQ8biqn4SN2azR7nCbO5tHnHeA,2945
28
+ rcdl-3.0.0b23.dist-info/RECORD,,