@@ -34,10 +34,11 @@ def add_user(username, password):
34
34
click .echo (f"Created user { username } " )
35
35
36
36
@cli .command ()
37
- def scan_videos ():
37
+ @click .option ("--root" , "-r" , help = "root video path to scan" , required = False )
38
+ def scan_videos (root ):
38
39
with create_app ().app_context ():
39
40
paths = current_app .config ['PATHS' ]
40
- raw_videos = paths ["video" ]
41
+ videos_path = paths ["video" ]
41
42
video_links = paths ["processed" ] / "video_links"
42
43
43
44
config_file = open (paths ["data" ] / "config.json" )
@@ -47,13 +48,13 @@ def scan_videos():
47
48
if not video_links .is_dir ():
48
49
video_links .mkdir ()
49
50
50
- logger .info (f"Scanning { str (raw_videos )} for { ', ' .join (SUPPORTED_FILE_EXTENSIONS )} video files" )
51
- video_files = [f for f in raw_videos .glob ('**/*' ) if f .is_file () and f .suffix .lower () in SUPPORTED_FILE_EXTENSIONS ]
51
+ logger .info (f"Scanning { str (videos_path )} for { ', ' .join (SUPPORTED_FILE_EXTENSIONS )} video files" )
52
+ video_files = [f for f in ( videos_path / root if root else videos_path ) .glob ('**/*' ) if f .is_file () and f .suffix .lower () in SUPPORTED_FILE_EXTENSIONS ]
52
53
video_rows = Video .query .all ()
53
54
54
55
new_videos = []
55
56
for vf in video_files :
56
- path = str (vf .relative_to (raw_videos ))
57
+ path = str (vf .relative_to (videos_path ))
57
58
video_id = util .video_id (vf )
58
59
existing = next ((vr for vr in video_rows if vr .video_id == video_id ), None )
59
60
duplicate = next ((dvr for dvr in new_videos if dvr .video_id == video_id ), None )
@@ -64,16 +65,16 @@ def scan_videos():
64
65
logger .info (f"Updating Video { video_id } , available=True" )
65
66
db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "available" : True })
66
67
if not existing .created_at :
67
- created_at = datetime .fromtimestamp (os .path .getctime (f"{ raw_videos } /{ path } " ))
68
+ created_at = datetime .fromtimestamp (os .path .getctime (f"{ videos_path } /{ path } " ))
68
69
logger .info (f"Updating Video { video_id } , created_at={ created_at } " )
69
70
db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "created_at" : created_at })
70
71
if not existing .updated_at :
71
- updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ raw_videos } /{ path } " ))
72
+ updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ videos_path } /{ path } " ))
72
73
logger .info (f"Updating Video { video_id } , updated_at={ updated_at } " )
73
74
db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "updated_at" : updated_at })
74
75
else :
75
- created_at = datetime .fromtimestamp (os .path .getctime (f"{ raw_videos } /{ path } " ))
76
- updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ raw_videos } /{ path } " ))
76
+ created_at = datetime .fromtimestamp (os .path .getctime (f"{ videos_path } /{ path } " ))
77
+ updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ videos_path } /{ path } " ))
77
78
v = Video (video_id = video_id , extension = vf .suffix , path = path , available = True , created_at = created_at , updated_at = updated_at )
78
79
logger .info (f"Adding new Video { video_id } at { str (path )} (created { created_at .isoformat ()} , updated { updated_at .isoformat ()} )" )
79
80
new_videos .append (v )
@@ -112,6 +113,83 @@ def scan_videos():
112
113
db .session .query (Video ).filter_by (video_id = ev .video_id ).update ({ "available" : False })
113
114
db .session .commit ()
114
115
116
+ @cli .command ()
117
+ @click .option ("--path" , "-p" , help = "path to video to scan" , required = False )
118
+ def scan_video (path ):
119
+ with create_app ().app_context ():
120
+ paths = current_app .config ['PATHS' ]
121
+ videos_path = paths ["video" ]
122
+ video_links = paths ["processed" ] / "video_links"
123
+
124
+ config_file = open (paths ["data" ] / "config.json" )
125
+ video_config = json .load (config_file )["app_config" ]["video_defaults" ]
126
+ config_file .close ()
127
+
128
+ if not video_links .is_dir ():
129
+ video_links .mkdir ()
130
+
131
+ video_file = (videos_path / path ) if (videos_path / path ).is_file () and (videos_path / path ).suffix .lower () in SUPPORTED_FILE_EXTENSIONS else None
132
+ if video_file :
133
+ video_rows = Video .query .all ()
134
+ logger .info (f"Scanning { str (video_file )} " )
135
+
136
+ path = str (video_file .relative_to (videos_path ))
137
+ video_id = util .video_id (video_file )
138
+ existing = next ((vr for vr in video_rows if vr .video_id == video_id ), None )
139
+ if existing :
140
+ if not existing .available :
141
+ logger .info (f"Updating Video { video_id } , available=True" )
142
+ db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "available" : True })
143
+ if not existing .created_at :
144
+ created_at = datetime .fromtimestamp (os .path .getctime (f"{ videos_path } /{ path } " ))
145
+ logger .info (f"Updating Video { video_id } , created_at={ created_at } " )
146
+ db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "created_at" : created_at })
147
+ if not existing .updated_at :
148
+ updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ videos_path } /{ path } " ))
149
+ logger .info (f"Updating Video { video_id } , updated_at={ updated_at } " )
150
+ db .session .query (Video ).filter_by (video_id = existing .video_id ).update ({ "updated_at" : updated_at })
151
+ else :
152
+ created_at = datetime .fromtimestamp (os .path .getctime (f"{ videos_path } /{ path } " ))
153
+ updated_at = datetime .fromtimestamp (os .path .getmtime (f"{ videos_path } /{ path } " ))
154
+ v = Video (video_id = video_id , extension = video_file .suffix , path = path , available = True , created_at = created_at , updated_at = updated_at )
155
+ logger .info (f"Adding new Video { video_id } at { str (path )} (created { created_at .isoformat ()} , updated { updated_at .isoformat ()} )" )
156
+ db .session .add (v )
157
+ fd = os .open (str (video_links .absolute ()), os .O_DIRECTORY )
158
+ src = Path ((paths ["video" ] / v .path ).absolute ())
159
+ dst = Path (paths ["processed" ] / "video_links" / (video_id + video_file .suffix ))
160
+ common_root = Path (* os .path .commonprefix ([src .parts , dst .parts ]))
161
+ num_up = len (dst .parts )- 1 - len (common_root .parts )
162
+ prefix = "../" * num_up
163
+ rel_src = Path (prefix + str (src ).replace (str (common_root ), '' ))
164
+ if not dst .exists ():
165
+ logger .info (f"Linking { str (rel_src )} --> { str (dst )} " )
166
+ try :
167
+ os .symlink (src , dst , dir_fd = fd )
168
+ except FileExistsError :
169
+ logger .info (f"{ dst } exists already" )
170
+ info = VideoInfo (video_id = v .video_id , title = Path (v .path ).stem , private = video_config ["private" ])
171
+ db .session .add (info )
172
+
173
+ processed_root = Path (current_app .config ['PROCESSED_DIRECTORY' ])
174
+ logger .info (f"Checking for videos with missing posters..." )
175
+ derived_path = Path (processed_root , "derived" , info .video_id )
176
+ video_path = Path (processed_root , "video_links" , info .video_id + video_file .suffix )
177
+ if video_path .exists ():
178
+ poster_path = Path (derived_path , "poster.jpg" )
179
+ should_create_poster = (not poster_path .exists () or regenerate )
180
+ if should_create_poster :
181
+ if not derived_path .exists ():
182
+ derived_path .mkdir (parents = True )
183
+ poster_time = 0
184
+ util .create_poster (video_path , derived_path / "poster.jpg" , poster_time )
185
+ else :
186
+ logger .debug (f"Skipping creation of poster for video { info .video_id } because it exists at { str (poster_path )} " )
187
+ db .session .commit ()
188
+ else :
189
+ logger .warn (f"Skipping creation of poster for video { info .video_id } because the video at { str (video_path )} does not exist or is not accessible" )
190
+ else :
191
+ logger .info (f"Invalid video file, unable to scan: { str (videos_path / path )} " )
192
+
115
193
@cli .command ()
116
194
def repair_symlinks ():
117
195
with create_app ().app_context ():
@@ -265,7 +343,8 @@ def create_boomerang_posters(regenerate):
265
343
266
344
@cli .command ()
267
345
@click .pass_context
268
- def bulk_import (ctx ):
346
+ @click .option ("--root" , "-r" , help = "root video path to scan" , required = False )
347
+ def bulk_import (ctx , root ):
269
348
with create_app ().app_context ():
270
349
paths = current_app .config ['PATHS' ]
271
350
if util .lock_exists (paths ["data" ]):
@@ -275,7 +354,7 @@ def bulk_import(ctx):
275
354
276
355
timing = {}
277
356
s = time .time ()
278
- ctx .invoke (scan_videos )
357
+ ctx .invoke (scan_videos , root = root )
279
358
timing ['scan_videos' ] = time .time () - s
280
359
s = time .time ()
281
360
ctx .invoke (sync_metadata )
0 commit comments