Search and RemoteControl

Discuss issues related to PS3 Media Server development (only for programmers)

Search and RemoteControl

Postby SharkHunter » Thu Dec 02, 2010 8:43 am

Hi all,

I've been struggling for a while with a new project. As it turns out the PMS lacked some functions (for this project at least), and it can't be like that can it? So I rolled up my shirt and got my hands all dirty.

Below are two patches (actually there are four files patched). One which allows the "Search" primitive to be used (not just XBOX), and one which allows remote controls to "push" media to renders.

The remote control feature is simple and only requires a config option "remote_control=true" in the PMS.conf. The remote control is a device that will browse the server and the push the data to a render. Without this patch the PMS was a bit confused when the redner asked for media it had not browsed itself.

The second patch enables searching. It is no rocket science here all chil discovering is done as normal and the it filters in the requset base on name, media info etc. However the saerch is prepared to be more intelligent than that. The search strin is passed down to the discoverChildren function (which now comes in two variants on with and one withou argument), by default the search string is just dropped and everything works as normal. But if you hav a search engine on the other side (like grooveshark,spotify,you tube etc.) you can override the discoverchildren(str) and send the string directly to the search engine. If you do override this method you must also override the isSearched function which then must return true. This function disables the output filter in request.

Questions?

Code: Select all
diff -rupN old/DLNAResource.java new/DLNAResource.java
--- old/DLNAResource.java   2010-12-02 08:17:12.407360200 +0100
+++ new/DLNAResource.java   2010-11-21 21:34:21.499845500 +0100
@@ -329,7 +329,13 @@ public abstract class DLNAResource exten
          }
    }
    
-   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count, RendererConfiguration renderer) throws IOException {
+   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count,
+         RendererConfiguration renderer) throws IOException {
+      return getDLNAResources(objectId,children,start,count,renderer,null);
+   }
+   
+   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count,
+            RendererConfiguration renderer,String searchStr) throws IOException {
       PMS.debug("Searching for objectId: " + objectId + " with children option: " +children);
       ArrayList<DLNAResource> resources = new ArrayList<DLNAResource>();
       DLNAResource resource = search(objectId);
@@ -361,7 +367,7 @@ public abstract class DLNAResource exten
             else {
                // Discovering if not already done.
                if (!resource.discovered) {
-                  resource.discoverChildren();
+                  resource.discoverChildren(searchStr);
                   boolean ready = true;
                   if (renderer.isMediaParserV2())
                      ready = resource.analyzeChildren(count);
@@ -434,6 +440,15 @@ public abstract class DLNAResource exten
       
    }
    
+   // Sharkpatch
+   public void discoverChildren(String str) {
+      discoverChildren();
+   }
+   
+   public boolean isSearched() {
+      return false;
+   }
+   
    public boolean analyzeChildren(int count) {
       return true;
    }
@@ -1023,6 +1038,16 @@ public abstract class DLNAResource exten
       return player;
    }
    
+   ////////////////////////////////////
+   // Shark patch
+   ////////////////////////////////////
+   public void setPlayer(Player p) {
+      player=p;
+   }
+   //////////////////////////////////////
+   // End patch
+   //////////////////////////////////////
+   
    public String mimeType() {
       if (player != null)
          return player.mimeType();
diff -rupN old/PMS.java new/PMS.java
--- old/PMS.java   2010-12-02 08:16:46.600884100 +0100
+++ new/PMS.java   2010-12-02 08:20:24.373340000 +0100
@@ -164,6 +164,14 @@ public class PMS {
       
    }
    
+   //////////////////////////////////////////////////////
+   // SharkHunter
+   //////////////////////////////////////////////////////
+   
+   public ArrayList<RendererConfiguration> getRenders() {
+      return foundRenderers;
+   }
+   
    //private RootFolder rootFolder;
    private HTTPServer server;
    private String serverName;
diff -rupN old/Request.java new/Request.java
--- old/Request.java   2010-12-02 08:16:22.108483300 +0100
+++ new/Request.java   2010-12-01 21:20:24.510357400 +0100
@@ -187,6 +187,27 @@ public class Request extends HTTPResourc
          String id = argument.substring(argument.indexOf("get/") + 4, argument.lastIndexOf("/"));
          id = id.replace("%24", "$"); // popcorn hour ?
          ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(id, false, 0, 0, mediaRenderer);
+         ///////////////////////////////////////////////
+         // Sharkpatch
+         ///////////////////////////////////////////////
+         if(files==null||files.size()==0) { // nothing found
+            String tmp=(String)PMS.getConfiguration().getCustomProperty("remote_control");
+            if(tmp!=null&&!tmp.equalsIgnoreCase("false")) {
+               ArrayList<RendererConfiguration> renders=PMS.get().getRenders();
+               for(int i=0;i<renders.size();i++) {
+                  RendererConfiguration r=renders.get(i);
+                  if(r.equals(mediaRenderer))
+                     continue;
+                  files = PMS.get().getRootFolder(r).getDLNAResources(id, false, 0, 0, r);
+                  if(files!=null&&files.size()!=0) {
+                     break;
+                  }
+               }
+            }
+         }
+         //////////////////////////////////////
+         // End patch
+         //////////////////////////////////////
          if (transferMode != null) {
             output(output, "TransferMode.DLNA.ORG: " + transferMode);
          }
@@ -342,7 +363,7 @@ public class Request extends HTTPResourc
             //PMS.debug(content);
             objectID = getEnclosingValue(content, "<ObjectID>", "</ObjectID>");
             String containerID = null;
-            if ((objectID == null || objectID.length() == 0) && xbox) {
+            if ((objectID == null || objectID.length() == 0) /*&& xbox*/) {
                containerID = getEnclosingValue(content, "<ContainerID>", "</ContainerID>");
                if (!containerID.contains("$")) {
                   objectID = "0";
@@ -396,13 +417,36 @@ public class Request extends HTTPResourc
                   }
                }
             }
-            
-            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount, mediaRenderer);
+            // Sharkpatch
+            else if (soapaction.contains("ContentDirectory:1#Search"))
+               searchCriteria=getEnclosingValue(content,"<SearchCriteria>","</SearchCriteria>");
+               
+            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount,
+                              mediaRenderer,searchCriteria);
             if (searchCriteria != null && files != null) {
                for(int i=files.size()-1;i>=0;i--) {
-                  if (!files.get(i).getName().equals(searchCriteria))
+                  searchCriteria=searchCriteria.toLowerCase();
+               for(int i=files.size()-1;i>=0;i--) {
+                  /*if (!files.get(i).getName().equals(searchCriteria))
+                     files.remove(i);*/
+                  DLNAResource res=files.get(i);
+                  if(res.isSearched())
+                     continue;
+                  boolean keep=res.getName().toLowerCase().indexOf(searchCriteria)!=-1;
+                  if(res.media!=null) {
+                     for(int j=0;j<res.media.audioCodes.size();j++) {
+                        DLNAMediaAudio audio=res.media.audioCodes.get(j);
+                        keep|=audio.album.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.artist.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.songname.toLowerCase().indexOf(searchCriteria)!=-1;
+                     }
+                  }
+                  if(!keep) // dump it
                      files.remove(i);
                }
+               if(xbox)
+               // Patch end
+               }
                if (files.size() > 0) {
                   files = files.get(0).getChildren();
                }
diff -rupN old/RequestV2.java new/RequestV2.java
--- old/RequestV2.java   2010-12-02 08:15:59.135169300 +0100
+++ new/RequestV2.java   2010-11-21 21:35:26.598568900 +0100
@@ -30,6 +30,7 @@ import java.util.TimeZone;
 
 import net.pms.PMS;
 import net.pms.configuration.RendererConfiguration;
+import net.pms.dlna.DLNAMediaAudio;
 import net.pms.dlna.DLNAMediaInfo;
 import net.pms.dlna.DLNAResource;
 
@@ -180,6 +181,27 @@ public class RequestV2 extends HTTPResou
          String id = argument.substring(argument.indexOf("get/") + 4, argument.lastIndexOf("/"));
          id = id.replace("%24", "$"); // popcorn hour ?
          ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(id, false, 0, 0, mediaRenderer);
+         ///////////////////////////////////////////////
+         // Sharkpatch
+         ///////////////////////////////////////////////
+         if(files==null||files.size()==0) { // nothing found
+            String tmp=(String)PMS.getConfiguration().getCustomProperty("remote_control");
+            if(tmp!=null&&!tmp.equalsIgnoreCase("false")) {
+               ArrayList<RendererConfiguration> renders=PMS.get().getRenders();
+               for(int i=0;i<renders.size();i++) {
+                  RendererConfiguration r=renders.get(i);
+                  if(r.equals(mediaRenderer))
+                     continue;
+                  files = PMS.get().getRootFolder(r).getDLNAResources(id, false, 0, 0, r);
+                  if(files!=null&&files.size()!=0) {
+                     break;
+                  }
+               }
+            }
+         }
+         //////////////////////////////////////
+         // End patch
+         //////////////////////////////////////
          if (transferMode != null) {
             output.setHeader("TransferMode.DLNA.ORG", transferMode);
          }
@@ -350,7 +372,8 @@ public class RequestV2 extends HTTPResou
             //PMS.debug(content);
             objectID = getEnclosingValue(content, "<ObjectID>", "</ObjectID>");
             String containerID = null;
-            if ((objectID == null || objectID.length() == 0) && xbox) {
+            // Sharkpatch
+            if ((objectID == null || objectID.length() == 0) /*&& xbox*/) {
                containerID = getEnclosingValue(content, "<ContainerID>", "</ContainerID>");
                if (!containerID.contains("$")) {
                   objectID = "0";
@@ -380,7 +403,8 @@ public class RequestV2 extends HTTPResou
             
             response.append(HTTPXMLHelper.DIDL_HEADER);
             
-            if (soapaction.contains("ContentDirectory:1#Search"))
+            
+            if (soapaction.contains("ContentDirectory:1#Search"))
                browseFlag = "BrowseDirectChildren";
             
             //XBOX virtual containers ... doh
@@ -405,12 +429,34 @@ public class RequestV2 extends HTTPResou
                }
             }
             
-            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount, mediaRenderer);
+            // Sharkpatch
+            else if (soapaction.contains("ContentDirectory:1#Search"))
+               searchCriteria=getEnclosingValue(content,"<SearchCriteria>","</SearchCriteria>");
+            
+            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount,
+                     mediaRenderer,searchCriteria);
             if (searchCriteria != null && files != null) {
+               searchCriteria=searchCriteria.toLowerCase();
                for(int i=files.size()-1;i>=0;i--) {
-                  if (!files.get(i).getName().equals(searchCriteria))
+                  /*if (!files.get(i).getName().equals(searchCriteria))
+                     files.remove(i);*/
+                  DLNAResource res=files.get(i);
+                  if(res.isSearched())
+                     continue;
+                  boolean keep=res.getName().toLowerCase().indexOf(searchCriteria)!=-1;
+                  if(res.media!=null) {
+                     for(int j=0;j<res.media.audioCodes.size();j++) {
+                        DLNAMediaAudio audio=res.media.audioCodes.get(j);
+                        keep|=audio.album.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.artist.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.songname.toLowerCase().indexOf(searchCriteria)!=-1;
+                     }
+                  }
+                  if(!keep) // dump it
                      files.remove(i);
                }
+               if(xbox)
+               // Patch end
                if (files.size() > 0) {
                   files = files.get(0).getChildren();
                }
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Re: Search and RemoteControl

Postby ExSport » Fri Dec 03, 2010 5:50 pm

I don't get it :mrgreen:
Please could you describe it more clearly (for dumbs like me) what these two changes exactly do?
Anyway many thanks for it 8-)
ExSport
 
Posts: 2166
Joined: Mon Jan 19, 2009 5:40 pm

Re: Search and RemoteControl

Postby SharkHunter » Fri Dec 03, 2010 9:51 pm

As always I'm more of a hacker then a documenter :D. Anyway, once agian:
1) One of the patches adds support for "search". In DLNA/UPnP there are two primitives (search and browse). Browse is what PMS supports now (you click your way around in some sort of directory/folder structure from the "render"). Search on the other and allows the render to send a search string to the server and then allow the server to pass back those entries that matches this search string. Very few servers I've tried supports search (and even fever renders). But since I can't live with such holes I plugged both. The search can be used as is in the patch (everything is working) but you could be more efficient towards places like youtube etc. and continue to pass the search string direct to them. Thats the nonsense about discoverChildern...

2) Remote control support. DLNA/UPnP supports remote controling. You use one device to browse/search the server and then another device(=render) to view/listen to the media on. The trouble for PMS was that the file tree was render based. That is render A had its tree and render B his tree. If you browsed in via a remote control and then ordered a render to play this media file PMS would look up the render and say "this file cannot be found in your tree". The patch plugs this hole, but I added a config option so people can activate this feature if they like it on.

As always when shipping code there sneaks in some small bugs in it. The observant reader could find the bug in Request.java.
Otherwise I'll fix it tomorrow.
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Re: Search and RemoteControl

Postby lightglitch » Sun Dec 05, 2010 2:40 am

Hi, very nice.
Does the ps3 supports the search function?
What media client did you use for testing?
The patch is for the r412 version?
lightglitch a.k.a Mário Franco
lightglitch
Project Member
 
Posts: 113
Joined: Mon Jun 22, 2009 2:58 pm

Re: Search and RemoteControl

Postby SharkHunter » Sun Dec 05, 2010 8:47 am

Patch i smade towards 409 but the areas in the code are not modified in 412. Don't know how to search on PS3 (nor on bravia XBOX etc.) since it has no keyboard. I used my own client :) . An android remote ctrl app (for searching). Media clients that i played media on is Bravia, XMBC,Andriod.
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Re: Search and RemoteControl

Postby SharkHunter » Sun Dec 26, 2010 9:29 pm

Found some bugs in the Search department. Solved that.
This patch contains the render image fix as well.

Code: Select all
Index: net/pms/dlna/DLNAResource.java
===================================================================
--- net/pms/dlna/DLNAResource.java   (revision 410)
+++ net/pms/dlna/DLNAResource.java   (working copy)
@@ -329,7 +329,13 @@
          }
    }
    
-   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count, RendererConfiguration renderer) throws IOException {
+   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count,
+         RendererConfiguration renderer) throws IOException {
+      return getDLNAResources(objectId,children,start,count,renderer,null);
+   }
+   
+   public synchronized ArrayList<DLNAResource> getDLNAResources(String objectId, boolean children, int start, int count,
+            RendererConfiguration renderer,String searchStr) throws IOException {
       PMS.debug("Searching for objectId: " + objectId + " with children option: " +children);
       ArrayList<DLNAResource> resources = new ArrayList<DLNAResource>();
       DLNAResource resource = search(objectId);
@@ -340,7 +346,7 @@
             if (!children) {
                resources.add(resource);
                if (resource.discovered) {
-                  if (resource.refreshChildren()) {
+                  if (resource.refreshChildren(searchStr)) {
                      resource.closeChildren(resource.childrenNumber, true);
                      resource.updateId++;
                      /*TranscodeVirtualFolder vf = null;
@@ -359,9 +365,17 @@
                }
             }
             else {
+               // Sharkpatch
+               if(resource.discovered) {
+                  if(searchStr!=null) {
+                     resource.discovered=false;
+                     resource.childrenNumber=0;
+                     resource.children.clear();
+                  }
+               }
                // Discovering if not already done.
                if (!resource.discovered) {
-                  resource.discoverChildren();
+                  resource.discoverChildren(searchStr);
                   boolean ready = true;
                   if (renderer.isMediaParserV2())
                      ready = resource.analyzeChildren(count);
@@ -378,6 +392,8 @@
                if (count == 0) {
                        count = resource.children.size();
                    }
+               if(count==0)
+                  return null;
                ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(count);
             
                int parallel_thread_number = 3;
@@ -434,10 +450,24 @@
       
    }
    
+   // Sharkpatch
+   public void discoverChildren(String str) {
+      discoverChildren();
+   }
+   
+   public boolean isSearched() {
+      return false;
+   }
+   
    public boolean analyzeChildren(int count) {
       return true;
    }
    
+   // Sharkpatch
+   public boolean refreshChildren(String str) {
+      return refreshChildren();
+   }
+   
    public boolean refreshChildren() {
       return false;
    }
@@ -1023,6 +1053,16 @@
       return player;
    }
    
+   ////////////////////////////////////
+   // Shark patch
+   ////////////////////////////////////
+   public void setPlayer(Player p) {
+      player=p;
+   }
+   //////////////////////////////////////
+   // End patch
+   //////////////////////////////////////
+   
    public String mimeType() {
       if (player != null)
          return player.mimeType();
Index: net/pms/dlna/RealFile.java
===================================================================
--- net/pms/dlna/RealFile.java   (revision 410)
+++ net/pms/dlna/RealFile.java   (working copy)
@@ -73,6 +73,8 @@
    
    private List<File> discoverable;
 
+   
+   
    @Override
    public void discoverChildren() {
       super.discoverChildren();
@@ -98,12 +100,12 @@
          });
       }
       for(File f:files) {
-         if (f.isDirectory())
+         if (f.isDirectory())
             discoverable.add(f);//manageFile(f);
       }
       for(File f:files) {
-         if (f.isFile())
-            discoverable.add(f);//manageFile(f);
+         if (f.isFile())
+               discoverable.add(f);//manageFile(f);
       }
    }
    
Index: net/pms/network/Request.java
===================================================================
--- net/pms/network/Request.java   (revision 410)
+++ net/pms/network/Request.java   (working copy)
@@ -33,6 +33,7 @@
 
 import net.pms.PMS;
 import net.pms.configuration.RendererConfiguration;
+import net.pms.dlna.DLNAMediaAudio;
 import net.pms.dlna.DLNAMediaInfo;
 import net.pms.dlna.DLNAResource;
 
@@ -187,6 +188,27 @@
          String id = argument.substring(argument.indexOf("get/") + 4, argument.lastIndexOf("/"));
          id = id.replace("%24", "$"); // popcorn hour ?
          ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(id, false, 0, 0, mediaRenderer);
+         ///////////////////////////////////////////////
+         // Sharkpatch
+         ///////////////////////////////////////////////
+         if(files==null||files.size()==0) { // nothing found
+            String tmp=(String)PMS.getConfiguration().getCustomProperty("remote_control");
+            if(tmp!=null&&!tmp.equalsIgnoreCase("false")) {
+               ArrayList<RendererConfiguration> renders=PMS.get().getRenders();
+               for(int i=0;i<renders.size();i++) {
+                  RendererConfiguration r=renders.get(i);
+                  if(r.equals(mediaRenderer))
+                     continue;
+                  files = PMS.get().getRootFolder(r).getDLNAResources(id, false, 0, 0, r);
+                  if(files!=null&&files.size()!=0) {
+                     break;
+                  }
+               }
+            }
+         }
+         //////////////////////////////////////
+         // End patch
+         //////////////////////////////////////
          if (transferMode != null) {
             output(output, "TransferMode.DLNA.ORG: " + transferMode);
          }
@@ -342,7 +364,7 @@
             //PMS.debug(content);
             objectID = getEnclosingValue(content, "<ObjectID>", "</ObjectID>");
             String containerID = null;
-            if ((objectID == null || objectID.length() == 0) && xbox) {
+            if ((objectID == null || objectID.length() == 0) /*&& xbox*/) {
                containerID = getEnclosingValue(content, "<ContainerID>", "</ContainerID>");
                if (!containerID.contains("$")) {
                   objectID = "0";
@@ -396,13 +418,36 @@
                   }
                }
             }
-            
-            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount, mediaRenderer);
+            // Sharkpatch
+            else if (soapaction.contains("ContentDirectory:1#Search"))
+               searchCriteria=getEnclosingValue(content,"<SearchCriteria>","</SearchCriteria>");
+               
+            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount,
+                              mediaRenderer,searchCriteria);
             if (searchCriteria != null && files != null) {
                for(int i=files.size()-1;i>=0;i--) {
-                  if (!files.get(i).getName().equals(searchCriteria))
+                  searchCriteria=searchCriteria.toLowerCase();
+               //for(int i=files.size()-1;i>=0;i--) {
+                  /*if (!files.get(i).getName().equals(searchCriteria))
+                     files.remove(i);*/
+                  DLNAResource res=files.get(i);
+                  if(res.isSearched())
+                     continue;
+                  boolean keep=res.getName().toLowerCase().indexOf(searchCriteria)!=-1;
+                  if(res.media!=null) {
+                     for(int j=0;j<res.media.audioCodes.size();j++) {
+                        DLNAMediaAudio audio=res.media.audioCodes.get(j);
+                        keep|=audio.album.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.artist.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.songname.toLowerCase().indexOf(searchCriteria)!=-1;
+                     }
+                  }
+                  if(!keep) // dump it
                      files.remove(i);
                }
+               if(xbox)
+               // Patch end
+               
                if (files.size() > 0) {
                   files = files.get(0).getChildren();
                }
Index: net/pms/network/RequestV2.java
===================================================================
--- net/pms/network/RequestV2.java   (revision 410)
+++ net/pms/network/RequestV2.java   (working copy)
@@ -30,6 +30,7 @@
 
 import net.pms.PMS;
 import net.pms.configuration.RendererConfiguration;
+import net.pms.dlna.DLNAMediaAudio;
 import net.pms.dlna.DLNAMediaInfo;
 import net.pms.dlna.DLNAResource;
 
@@ -180,6 +181,27 @@
          String id = argument.substring(argument.indexOf("get/") + 4, argument.lastIndexOf("/"));
          id = id.replace("%24", "$"); // popcorn hour ?
          ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(id, false, 0, 0, mediaRenderer);
+         ///////////////////////////////////////////////
+         // Sharkpatch
+         ///////////////////////////////////////////////
+         if(files==null||files.size()==0) { // nothing found
+            String tmp=(String)PMS.getConfiguration().getCustomProperty("remote_control");
+            if(tmp!=null&&!tmp.equalsIgnoreCase("false")) {
+               ArrayList<RendererConfiguration> renders=PMS.get().getRenders();
+               for(int i=0;i<renders.size();i++) {
+                  RendererConfiguration r=renders.get(i);
+                  if(r.equals(mediaRenderer))
+                     continue;
+                  files = PMS.get().getRootFolder(r).getDLNAResources(id, false, 0, 0, r);
+                  if(files!=null&&files.size()!=0) {
+                     break;
+                  }
+               }
+            }
+         }
+         //////////////////////////////////////
+         // End patch
+         //////////////////////////////////////
          if (transferMode != null) {
             output.setHeader("TransferMode.DLNA.ORG", transferMode);
          }
@@ -350,7 +372,8 @@
             //PMS.debug(content);
             objectID = getEnclosingValue(content, "<ObjectID>", "</ObjectID>");
             String containerID = null;
-            if ((objectID == null || objectID.length() == 0) && xbox) {
+            // Sharkpatch
+            if ((objectID == null || objectID.length() == 0) /*&& xbox*/) {
                containerID = getEnclosingValue(content, "<ContainerID>", "</ContainerID>");
                if (!containerID.contains("$")) {
                   objectID = "0";
@@ -380,7 +403,8 @@
             
             response.append(HTTPXMLHelper.DIDL_HEADER);
             
-            if (soapaction.contains("ContentDirectory:1#Search"))
+            
+            if (soapaction.contains("ContentDirectory:1#Search"))
                browseFlag = "BrowseDirectChildren";
             
             //XBOX virtual containers ... doh
@@ -405,12 +429,34 @@
                }
             }
             
-            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount, mediaRenderer);
+            // Sharkpatch
+            else if (soapaction.contains("ContentDirectory:1#Search"))
+               searchCriteria=getEnclosingValue(content,"<SearchCriteria>","</SearchCriteria>");
+            
+            ArrayList<DLNAResource> files = PMS.get().getRootFolder(mediaRenderer).getDLNAResources(objectID, browseFlag!=null&&browseFlag.equals("BrowseDirectChildren"), startingIndex, requestCount,
+                     mediaRenderer,searchCriteria);
             if (searchCriteria != null && files != null) {
+               searchCriteria=searchCriteria.toLowerCase();
                for(int i=files.size()-1;i>=0;i--) {
-                  if (!files.get(i).getName().equals(searchCriteria))
+                  /*if (!files.get(i).getName().equals(searchCriteria))
+                     files.remove(i);*/
+                  DLNAResource res=files.get(i);
+                  if(res.isSearched())
+                     continue;
+                  boolean keep=res.getName().toLowerCase().indexOf(searchCriteria)!=-1;
+                  if(res.media!=null) {
+                     for(int j=0;j<res.media.audioCodes.size();j++) {
+                        DLNAMediaAudio audio=res.media.audioCodes.get(j);
+                        keep|=audio.album.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.artist.toLowerCase().indexOf(searchCriteria)!=-1;
+                        keep|=audio.songname.toLowerCase().indexOf(searchCriteria)!=-1;
+                     }
+                  }
+                  if(!keep) // dump it
                      files.remove(i);
                }
+               if(xbox)
+               // Patch end
                if (files.size() > 0) {
                   files = files.get(0).getChildren();
                }
Index: net/pms/newgui/StatusTab.java
===================================================================
--- net/pms/newgui/StatusTab.java   (revision 410)
+++ net/pms/newgui/StatusTab.java   (working copy)
@@ -20,6 +20,8 @@
 
 import java.awt.Font;
 import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -29,6 +31,7 @@
 import javax.swing.JProgressBar;
 
 import net.pms.Messages;
+import net.pms.PMS;
 
 import com.jgoodies.forms.builder.PanelBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
@@ -141,6 +144,8 @@
             InputStream is = LooksFrame.class.getResourceAsStream("/resources/images/clients/" + icon);
             if (is == null)
                is = LooksFrame.class.getResourceAsStream("/renderers/" + icon);
+            if(is==null) // assume full path
+               is=new FileInputStream(new File(icon));
             if (is != null)
                bi = ImageIO.read(is); //$NON-NLS-1$
          } catch (IOException e) {
Index: net/pms/PMS.java
===================================================================
--- net/pms/PMS.java   (revision 410)
+++ net/pms/PMS.java   (working copy)
@@ -122,7 +122,7 @@
 public class PMS {
    
    private static final String UPDATE_SERVER_URL = "http://ps3mediaserver.googlecode.com/svn/trunk/ps3mediaserver/update.data"; //$NON-NLS-1$
-   public static final String VERSION = "1.20.409"; //$NON-NLS-1$
+   public static final String VERSION = "1.20.409c"; //$NON-NLS-1$
    public static final String AVS_SEPARATOR = "\1"; //$NON-NLS-1$
 
    // TODO(tcox):  This shouldn't be static
@@ -164,6 +164,14 @@
       
    }
    
+   //////////////////////////////////////////////////////
+   // SharkHunter
+   //////////////////////////////////////////////////////
+   
+   public ArrayList<RendererConfiguration> getRenders() {
+      return foundRenderers;
+   }
+   
    //private RootFolder rootFolder;
    private HTTPServer server;
    private String serverName;
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Re: Search and RemoteControl

Postby puntloos » Thu Nov 17, 2011 7:38 pm

SharkHunter wrote:As always I'm more of a hacker then a documenter :D. Anyway, once agian:
1) One of the patches adds support for "search". In DLNA/UPnP there are two primitives (search and browse). Browse is what PMS supports now (you click your way around in some sort of directory/folder structure from the "render"). Search on the other and allows the render to send a search string to the server and then allow the server to pass back those entries that matches this search string. Very few servers I've tried supports search (and even fever renders). But since I can't live with such holes I plugged both. The search can be used as is in the patch (everything is working) but you could be more efficient towards places like youtube etc. and continue to pass the search string direct to them. Thats the nonsense about discoverChildern...

2) Remote control support. DLNA/UPnP supports remote controling. You use one device to browse/search the server and then another device(=render) to view/listen to the media on. The trouble for PMS was that the file tree was render based. That is render A had its tree and render B his tree. If you browsed in via a remote control and then ordered a render to play this media file PMS would look up the render and say "this file cannot be found in your tree". The patch plugs this hole, but I added a config option so people can activate this feature if they like it on.

As always when shipping code there sneaks in some small bugs in it. The observant reader could find the bug in Request.java.
Otherwise I'll fix it tomorrow.

Just one important question:

Does the PS3 support rendering video that is pushed to it? Can I use my PC (where ps3mediaserver runs) or an android phone to select the actual source media, rather than clumsily using the PS3 XMB to find the file I want to play?
puntloos
 
Posts: 51
Joined: Thu Nov 26, 2009 7:33 pm

Re: Search and RemoteControl

Postby SharkHunter » Mon Nov 21, 2011 10:05 am

Thats the idea. Works on Bravia and on my XOOM (and my arc). Haven't tried PS3
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Re: Search and RemoteControl

Postby dundanox » Fri Dec 16, 2011 6:03 pm

hi, i have the sony bravia KDL-46V5800 (firmware: 1.740SA) as render, the BubbleUPnP app for android as remote controler and PS3MediaServer 1.50 as server. I can search the libary but playing a file (music or video) i get the error: Action SetAVTransportURI failed (code 714). Anybody know what the problem is?
dundanox
 
Posts: 4
Joined: Wed Dec 30, 2009 11:38 am

Re: Search and RemoteControl

Postby SharkHunter » Mon Dec 19, 2011 4:05 pm

Yes, thats the illegal mime error. This means that the BubbleUpnp doesn't take care of the transcoding etc. that PMS can handle. PMS reports that the media is of mime type x and then when the remote then sends this info to the bravia the bravia doesn't support this type. The remote should "translate" the mime type to something the bravia can handle. Do I need to say that SharkMote does this? :)
SharkHunter
 
Posts: 941
Joined: Tue Jun 01, 2010 8:39 pm

Next

Return to Developers

Who is online

Users browsing this forum: No registered users and 2 guests