11import os
2+ from urllib .parse import quote
23
34import pytest
45
@@ -51,7 +52,12 @@ def test_library_page_has_mode_tabs_and_no_masonry_label(client):
5152 assert "scheduleWaterfallRelayout" in body
5253 assert "flow_ui_shared.js" in body
5354 assert "flow_state_controller.js" in body
55+ assert "flow_session.js" in body
56+ assert "flow_actions_shared.js" in body
57+ assert "flow_media_actions_controller.js" in body
5458 assert "createFlowStateController(" in body
59+ assert "createFlowSession(" in body
60+ assert "createFlowMediaActionsController(" in body
5561 assert "uiShared.updateMagnifierContent({" in body
5662
5763
@@ -62,7 +68,12 @@ def test_home_feed_uses_unified_immersive_model(client):
6268 assert "body.immersive-mode .caption-panel:not(.is-hidden)" in body
6369 assert "flow_ui_shared.js" in body
6470 assert "flow_state_controller.js" in body
71+ assert "flow_session.js" in body
72+ assert "flow_actions_shared.js" in body
73+ assert "flow_media_actions_controller.js" in body
6574 assert "createFlowStateController(" in body
75+ assert "createFlowSession(" in body
76+ assert "createFlowMediaActionsController(" in body
6677 assert "flowState.toggleImmersive()" in body
6778 assert "flowState.setMagnifying(active)" in body
6879 assert "uiShared.updateMagnifierContent({" in body
@@ -139,19 +150,18 @@ def test_api_library_items_dedupes_symlink_aliases(tmp_path, monkeypatch):
139150 assert video_items [0 ]["name" ] in {"origin.mp4" , "alias.mp4" }
140151
141152
142- def test_legacy_browse_and_gallery_redirects (client ):
143- browse = client .get ("/browse" , follow_redirects = False )
144- assert browse .status_code in {301 , 302 , 308 }
145- assert browse .headers .get ("Location" , "" ).startswith ("/library?mode=video_latest" )
153+ def test_removed_legacy_routes_and_apis_return_404 (client ):
154+ browse = client .get ("/browse" )
155+ assert browse .status_code == 404
146156
147- browse_big = client .get ("/browse?filter=big&min_mb=3" , follow_redirects = False )
148- assert browse_big .status_code in {301 , 302 , 308 }
149- assert "mode=big_files" in browse_big .headers .get ("Location" , "" )
150- assert "min_mb=3" in browse_big .headers .get ("Location" , "" )
157+ gallery = client .get ("/gallery" )
158+ assert gallery .status_code == 404
151159
152- gallery = client .get ("/gallery" , follow_redirects = False )
153- assert gallery .status_code in {301 , 302 , 308 }
154- assert gallery .headers .get ("Location" , "" ).startswith ("/library?mode=image_random" )
160+ api_videos = client .get ("/api/videos" )
161+ assert api_videos .status_code == 404
162+
163+ api_random_images = client .get ("/api/random-images?page=1&size=10" )
164+ assert api_random_images .status_code == 404
155165
156166
157167def test_favorite_scope_and_detail_links (client ):
@@ -166,3 +176,37 @@ def test_favorite_scope_and_detail_links(client):
166176 assert "i01.jpg" in names
167177 assert any (item ["detail_url" ] == "/detail/v01.mp4" for item in data ["items" ])
168178 assert any (item ["detail_url" ] == "/image?uri=i01.jpg" for item in data ["items" ])
179+
180+
181+ def test_special_chars_in_media_urls_are_encoded (tmp_path , monkeypatch ):
182+ media_root = tmp_path / "media"
183+ media_root .mkdir (parents = True , exist_ok = True )
184+ video_name = "v#1+.mp4"
185+ image_name = "a&b.jpg"
186+ (media_root / video_name ).write_bytes (b"video" )
187+ (media_root / image_name ).write_bytes (b"image" )
188+
189+ data_root = tmp_path / "tiklocal-data"
190+ monkeypatch .setenv ("MEDIA_ROOT" , str (media_root ))
191+ monkeypatch .setenv ("TIKLOCAL_INSTANCE" , str (data_root ))
192+ app = create_app ({"TESTING" : True , "MEDIA_ROOT" : media_root })
193+ local_client = app .test_client ()
194+
195+ video_detail = local_client .get (f"/detail/{ quote (video_name , safe = '' )} " )
196+ assert video_detail .status_code == 200
197+ video_body = video_detail .data .decode ("utf-8" )
198+ assert 'src="/media/v%231%2B.mp4"' in video_body
199+ assert 'poster="/thumb?uri=v%231%2B.mp4"' in video_body
200+ assert "const fileName = \" v#1+.mp4\" ;" in video_body
201+
202+ image_detail = local_client .get (f"/image?uri={ quote (image_name , safe = '' )} " )
203+ assert image_detail .status_code == 200
204+ image_body = image_detail .data .decode ("utf-8" )
205+ assert 'src="/media?uri=a%26b.jpg"' in image_body
206+ assert "const imageUri = \" a\\ u0026b.jpg\" ;" in image_body
207+ assert "const imageUriEncoded = \" a%26b.jpg\" ;" in image_body
208+ assert "window.location.href = '/delete?uri=a%26b.jpg';" in image_body
209+
210+ media_res = local_client .get (f"/media?uri={ quote (video_name , safe = '' )} " , follow_redirects = False )
211+ assert media_res .status_code in {301 , 302 , 308 }
212+ assert media_res .headers .get ("Location" , "" ).endswith ("/media/v%231%2B.mp4" )
0 commit comments