1919package de .yaacc .upnp .server .contentdirectory ;
2020
2121import android .content .Context ;
22- import android .content .SharedPreferences ;
23- import android .media .MediaMetadataRetriever ;
2422import android .net .Uri ;
2523import android .provider .DocumentsContract ;
2624import android .util .Base64 ;
2725
2826import androidx .documentfile .provider .DocumentFile ;
29- import androidx .preference .PreferenceManager ;
3027
3128import org .fourthline .cling .support .model .DIDLObject ;
32- import org .fourthline .cling .support .model .Protocol ;
3329import org .fourthline .cling .support .model .ProtocolInfo ;
34- import org .fourthline .cling .support .model .Res ;
3530import org .fourthline .cling .support .model .SortCriterion ;
3631import org .fourthline .cling .support .model .container .Container ;
3732import org .fourthline .cling .support .model .container .StorageFolder ;
38- import org .fourthline .cling .support .model .item .AudioItem ;
39- import org .fourthline .cling .support .model .item .ImageItem ;
4033import org .fourthline .cling .support .model .item .Item ;
41- import org .fourthline .cling .support .model .item .VideoItem ;
4234import org .seamless .util .MimeType ;
4335
4436import java .util .ArrayList ;
5143import de .yaacc .upnp .model .YaaccRes ;
5244import de .yaacc .util .SAFCacheManager ;
5345import de .yaacc .util .SAFMetadata ;
54- import de .yaacc .util .FormatHelper ;
5546import de .yaacc .util .YaaccLogger ;
5647
5748/**
@@ -64,7 +55,7 @@ public class SafFolderBrowser extends ContentBrowser {
6455 public SafFolderBrowser (Context context ) {
6556 super (context );
6657 }
67-
58+
6859 @ Override
6960 public DIDLObject browseMeta (YaaccContentDirectory contentDirectory , String myId , long firstResult , long maxResults , SortCriterion [] orderby ) {
7061 if (myId .equals (ContentDirectoryIDs .SAF_FOLDER .getId ())) {
@@ -151,12 +142,12 @@ public List<Container> browseContainer(YaaccContentDirectory contentDirectory, S
151142 YaaccLogger .d (getClass ().getName (), "Browsing subfolder with ID: " + myId );
152143 String shortId = myId .substring (ContentDirectoryIDs .SAF_PREFIX .getId ().length ());
153144 String path = SAFCacheManager .getInstance (getContext ()).getUriForShortId (shortId );
154-
145+
155146 if (path == null ) {
156147 YaaccLogger .e (getClass ().getName (), "Short ID not found: " + shortId );
157148 return result ;
158149 }
159-
150+
160151 YaaccLogger .d (getClass ().getName (), "Resolved path from shortId " + shortId + ": " + path );
161152
162153 Uri uri = Uri .parse (path );
@@ -176,11 +167,11 @@ public List<Container> browseContainer(YaaccContentDirectory contentDirectory, S
176167 long listStart = System .currentTimeMillis ();
177168 DocumentFile [] files = root .listFiles ();
178169 YaaccLogger .d (getClass ().getName (), "listFiles() took " + (System .currentTimeMillis () - listStart ) + "ms, found " + files .length + " items" );
179-
170+
180171 int start = (int ) Math .max (0 , firstResult );
181172 int end = (int ) Math .min (files .length , start + maxResults );
182173 YaaccLogger .d (getClass ().getName (), "Pagination: start=" + start + ", end=" + end + ", total=" + files .length );
183-
174+
184175 for (int i = start ; i < end ; i ++) {
185176 long itemStart = System .currentTimeMillis ();
186177 DocumentFile file = files [i ];
@@ -238,7 +229,12 @@ public List<Item> browseItem(YaaccContentDirectory contentDirectory, String myId
238229 DocumentFile file = DocumentFile .fromSingleUri (getContext (), Uri .parse (path ));
239230 if (file != null && !file .isDirectory ()) {
240231 Item item = createItem (contentDirectory , path , file , myId , !file .canRead ());
241- if (item != null ) result .add (item );
232+ if (item != null ) {
233+ result .add (item );
234+ YaaccLogger .d (getClass ().getName (), "✓ Added to result: Item[" + (result .size () - 1 ) + "] " + (file .getName () != null ? file .getName () : "unknown" ));
235+ } else {
236+ YaaccLogger .d (getClass ().getName (), "✗ Skipped (null item): " + (file .getName () != null ? file .getName () : "unknown" ));
237+ }
242238 YaaccLogger .d (getClass ().getName (), "Item[" + i + "] " + (file .getName () != null ? file .getName () : "unknown" ) + " (took " + (System .currentTimeMillis () - itemStart ) + "ms)" );
243239 }
244240 }
@@ -249,26 +245,26 @@ public List<Item> browseItem(YaaccContentDirectory contentDirectory, String myId
249245 YaaccLogger .d (getClass ().getName (), "Browsing subfolder items for: " + myId );
250246 String shortId = myId .substring (ContentDirectoryIDs .SAF_PREFIX .getId ().length ());
251247 String path = SAFCacheManager .getInstance (getContext ()).getUriForShortId (shortId );
252-
248+
253249 if (path == null ) {
254250 YaaccLogger .e (getClass ().getName (), "Short ID not found: " + shortId );
255251 return result ;
256252 }
257-
253+
258254 long treeStart = System .currentTimeMillis ();
259255 DocumentFile root = DocumentFile .fromTreeUri (getContext (), Uri .parse (path ));
260256 YaaccLogger .d (getClass ().getName (), "Tree URI resolved in " + (System .currentTimeMillis () - treeStart ) + "ms" );
261-
257+
262258 if (root != null && root .isDirectory ()) {
263259 if (root .canRead ()) {
264260 long listStart = System .currentTimeMillis ();
265261 DocumentFile [] files = root .listFiles ();
266262 YaaccLogger .d (getClass ().getName (), "listFiles() took " + (System .currentTimeMillis () - listStart ) + "ms, found " + files .length + " items" );
267-
263+
268264 int start = (int ) Math .max (0 , firstResult );
269265 int end = (int ) Math .min (files .length , start + maxResults );
270266 YaaccLogger .d (getClass ().getName (), "Pagination: start=" + start + ", end=" + end + ", total=" + files .length );
271-
267+
272268 for (int i = start ; i < end ; i ++) {
273269 long itemStart = System .currentTimeMillis ();
274270 DocumentFile file = files [i ];
@@ -296,61 +292,80 @@ public List<Item> browseItem(YaaccContentDirectory contentDirectory, String myId
296292 private Item createItem (YaaccContentDirectory contentDirectory , String path , DocumentFile file , String parentId , boolean restricted ) {
297293 long createStart = System .currentTimeMillis ();
298294 String fileName = file .getName () != null ? file .getName () : "unknown" ;
299-
295+
300296 if (file .getName () != null && file .getName ().endsWith ("m3u" )) {
301297 return null ;
302298 }
303-
299+
304300 // Get all metadata from cache (duration, MIME type, short ID)
305301 SAFMetadata metadata = SAFCacheManager .getInstance (getContext ()).getMetadata (file );
306- if (metadata == null || metadata . mimeType == null ) {
302+ if (metadata == null ) {
307303 return null ;
308304 }
309305
310- MimeType mimeType = MimeType .valueOf (metadata .mimeType );
306+ // If MIME type is null or invalid, try to guess from filename
307+ String mimeTypeStr = metadata .mimeType ;
308+ if (mimeTypeStr == null || mimeTypeStr .equals ("null" ) || !mimeTypeStr .contains ("/" )) {
309+ mimeTypeStr = SAFCacheManager .getInstance (getContext ()).guessMimeTypeFromExtension (file .getName ());
310+ if (mimeTypeStr == null ) {
311+ return null ; // Still couldn't determine MIME type
312+ }
313+ }
314+
315+ MimeType mimeType = MimeType .valueOf (mimeTypeStr );
311316 String mimeTypeMain = mimeType .getType ();
312-
317+
313318 String id = ContentDirectoryIDs .SAF_PREFIX .getId () + metadata .shortId ;
314- String title = file .getName () != null ? file .getName () : path ;
319+ String title = file .getName () != null ? file .getName () : extractFilenameFromUri (path );
320+ if (file .getName () == null ) {
321+ YaaccLogger .d (getClass ().getName (), "file.getName() is null for URI: " + file .getUri ());
322+ }
323+
315324 if (restricted ) {
316325 title = "[X] " + title ;
317326 }
318-
327+
319328 // Use shortId in URI instead of Base64-encoded path
320329 String uri = getUriString (contentDirectory , id , mimeType , metadata .shortId );
321330 YaaccLogger .d (getClass ().getName (), "Generated URI for " + title + ": " + uri + " (shortId=" + metadata .shortId + ")" );
322-
331+
323332 long protocolStart = System .currentTimeMillis ();
324333 ProtocolInfo protocolInfo = getProtocolInfo (mimeType );
325334 long protocolTime = System .currentTimeMillis () - protocolStart ;
326-
335+
327336 String duration = null ;
328337 if (mimeTypeMain .equals ("audio" ) && !restricted ) {
329338 duration = metadata .duration ;
330339 }
331-
340+
332341 // Create lightweight YaaccRes (no Cling overhead)
333342 YaaccRes yaaccRes = new YaaccRes (protocolInfo , metadata .fileSize , duration , null , uri );
334-
343+
335344 // Create lightweight YaaccItem (no Cling Property overhead)
336345 long itemStart = System .currentTimeMillis ();
337- String clazz = mimeTypeMain .equals ("audio" ) ? "object.item.audioItem"
338- : mimeTypeMain .equals ("video" ) ? "object.item.videoItem"
339- : "object.item.imageItem" ;
346+ String clazz = mimeTypeMain .equals ("audio" ) ? "object.item.audioItem"
347+ : mimeTypeMain .equals ("video" ) ? "object.item.videoItem"
348+ : "object.item.imageItem" ;
340349 YaaccItem yaaccItem = new YaaccItem (id , parentId , title , "yaacc" , restricted , clazz );
341350 yaaccItem .addResource (yaaccRes );
342351 long itemTime = System .currentTimeMillis () - itemStart ;
343-
352+
344353 // Convert to Cling Item only at the end (for UPnP serialization)
345354 long convertStart = System .currentTimeMillis ();
346355 Item item = yaaccItem .toClingItem ();
347356 long convertTime = System .currentTimeMillis () - convertStart ;
348-
357+
349358 long totalTime = System .currentTimeMillis () - createStart ;
350359 YaaccLogger .d (getClass ().getName (), "Item[?] " + fileName + " - protocolInfo=" + protocolTime + "ms, YaaccItem=" + itemTime + "ms, convert=" + convertTime + "ms, total=" + totalTime + "ms" );
351360 return item ;
352361 }
353362
363+ private String extractFilenameFromUri (String path ) {
364+ if (path == null ) return "unknown" ;
365+ int lastSlash = path .lastIndexOf ('/' );
366+ return lastSlash >= 0 ? path .substring (lastSlash + 1 ) : path ;
367+ }
368+
354369 /*
355370 private void loadDurationAsync(DocumentFile file, Item item, Res res) {
356371
0 commit comments