MPAnywhere - a proof of concept for an MP2 webservice and webinterface (2 Viewers)

Status
Not open for further replies.

MJGraf

Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Dear community,

    I started this thread some time ago in the internal team forums, but we think it is time to share it with you. It is about three new server plugins for MP2 which - when they are ready - shall provide web services and a web interface for MP2. The reason for starting this thread was that a fellow Team MediaPortal member mentioned that it would be great to have a possibility to edit the metadata stored in our MP2 Server's MediaLibrary. We thought about a separate windows application such as the configuration utility for MP1. But somehow I preferred the idea to do such things in a browser - mainly because we are platform independent and there is no need to install yet another application. So i started reading about web interfaces and web services and we quickly realized that we could do much more things with a browser front end than edit metadata. When you read through this thread you will find a lot of ideas. Let's see how many of them we can realize...

    First of all, there is a reason why this thread is called "proof of concept". It means that these three plugins currently do not provide any benefit for a pure user of MP2. So if you are not interested in new technologies and you don't like to try new and cool software even if it is of no practical use, yet, this thread is probably not interesting for you.

    Technical Background of the Plugins

    For all the others I'll try to explain shortly what these plugins are about. As mentioned there are three plugins:
    • OwinService
    • MPAnywhereService
    • MPAnywhereService.Core
    OwinService
    OwinService provides the possibility to start "WebApps". To do so, it uses the Miscrosoft implementation of Owin, called Katana. A WebApp may contain any kind of service which is in most cases accessible via http and therefore e.g. via your browser. We currently support serving static files (to be able to provide a web interface) and ASP.NET WebAPI. We will probably also support SignalR and the OData extension of WebAPI.

    MPAnywhereService
    MPAnywhereService uses the OwinService to provide currently two WebApps. One serves static files on port 80, the other serves an ASP.NET WebAPI on port 81.
    The static file server is used to provide you with a web interface. This web interface uses Sencha ExtJS to provide you with a modern and snappy "single page application" in your browser. We will later also make use of Sencha Touch to have a tailor made interface for touch devices such as tablets and phones.

    MPAnywhereService.Core
    OwinService and MPAnywhereService were coded with the intention to be as extendable as anyhow possible by other plugins. Although we could have integrated all the functionality into the MPAnywhereService, I decided not to do so. Instead, MPAnywhereService itself only provides the groundwork for a web interface and web services. It will offer you a web interface - but with no usable functionality in it. It will offer you web services, but without the possibility to get useful data out of them. All this end-user useful functionality will be contained in MPAnywhereService.Core for two reasons: (1) I want to make sure that MPAnywhereService is actually extendable by other plugins. (2) Developers who want to extend MPAnywhereService can use MPAnywhereService.Core as a blueprint for their extensions.
    As mentioned before, there is no really useful functionality (such as the possibility to edit metadata), yet, but when it will be integrated, it will be in MPAnywhereService.Core.

    How to Try

    Enough background - let's get it started. You can download the latest version of the three plugins at the end of this post as zip file. The zip file contains two directories:
    • \SRC contains the complete source code for the plugins.
    • \BIN contains the compiled binaries which can be directly used with MP2.
    So if you want to try, stop your MP2 Server Service, copy the contents of the \BIN directory to the plugin directory of your MP2 Server and restart your MP2 Server. If you don't see anything but your MP2 Server starting, everything is fine.

    Now start a browser on any computer in your local network and type
    Code:
    http://[MP2_Server_Name]
    and of course replace [MP2_Server_Name] with the name or the IP address of the computer on which your MP2 Server is running. What you see is what I called "web interface" and it hopefully explains more than a thousand words...

    But i also talked about web services - in particular about ASP.NET WebAPI. To see what this is about, try
    Code:
    http://[MP2_Server_Name]:81/api/MediaItems
    http://[MP2_Server_Name]:81/api/MediaItems/[GUID]
    http://[MP2_Server_Name]:81/api/MediaItems?searchString=[SearchTerm]
    where [GUID] is the ID of a particular MediaItem in your MediaLibrary. If you don't know the GUIDs of your MediaItems, you can use the first line above to show all your MediaItems in your MediaLibrary, but be careful when you have 50k songs in it - it may be quite a lot of data ;)
    [SearchTerm] can be a part of any text field in your MediaLibrary. (Such as "heaven", "Clapton", etc. - but without the "")

    When you use FireFox, you will see your MediaItems as XML in your browser. When you use Internet Explorer, you are prompted to download a .json file. Please do so and open it with a text editor - and you will see the objects in Json format.

    That's basically all you can do for now. And I warned you: It is of no use, YET... But at least for me, it's quite cool already :p

    Why publish this thread if it's not ready, yet?

    Because WE NEED YOU :)

    But let me start from the beginning: As you will notice, this thread is public, but read only. The reason is that I want to keep this thread clean and focused on a purely technical discussion. When you read through this thread (and I encourage all of you, who were interested enough to read until here, to do so) you will realize that I used this thread as kind of a public memory and wrote down a lot of things I learned about web services in the last months. The reason is easy: I am no web developer. In my real live I'm not a developer at all. So for me all this stuff was new, but I found it interesting enough to write a lot of it down in this thread.

    This, however, does not mean that we don't want your comments on this. To the contrary! The main reason to publish this thread is to get your feedback and help. But please do so in the MPAnywhere Public Discussion Thread [INSERT LINK WHEN READY]. When should you post in that thread? Well.....
    • When you tried the plugins and they work
    • When you tried the plugins and they don't work
    • When you have an idea what else could be done with this
    • When you have an idea how the functionality you find in the plugins or the ideas in this thread can be improved
    • When you think we are on the wrong track and you have an idea how to do it better
    • When for other reasons you feel like posting something ;)
    But in particular, when the terms "ASP.NET WebAPI", "Owin", "Katana", "SignalR", "OData", "JavaScript", "Sencha ExtJS" or "Sencha Touch" sound familiar to you and you can imagine to help with this project, please post this in the other thread or drop me a pm. While I feel a bit better with the first five of these terms, I am still completely lost with JavaScript and Sencha. So if you have any experience in that area and you are willing to help, please let us know! The same applies if you are skilled in web design and have a cool idea on how the web interface may look better. As you can see from what I did, I may have some coding skills - but definitely no design skills ;)

    When you read through this thread, you will notice that there have already been some complete rewrites of the plugins. As a result, the information contained at the beginning of this thread is already outdated. But I did not want to edit all the threads to bring them up to date because I want to keep them as kind of a history so that interested people can still read why we went one route and not the other. When I find the time, I will create a few pages in our Wiki, where I will try to always have the latest structure and functionality explained. But please bear with me - this may take a while...

    When is this ready?
    This mainly depends on you ;) If we find 20 new and skilled developers willing to spend all their free time on this project, we may have this feature complete in 3 months. If we don't, it may take another 2 years until you can do something useful with it. So if you want to use this as soon as possible, please do not ask this question - but please help us to make it happen...

    And now let's get the discussion started in the other thread. And remember: There is no comment which is not useful (except for asking when it's ready ;) ). Please share all your thoughts - we need them!

    Michael

    -----------------------------------------------------------------------------------------------------------------------------

    [Original Thread]

    Hi everybody,

    I want to share something in a very, very, very early stage for discussion. It already works quite impressively for me - although it currently doesn't provide any benefit for the user, yet. I cannot rule out that there are still a lot of bugs and I know for sure that there are for MP2 purposes many many code comments missing and a general code cleanup is also necessary. This is the reason why I did not post in this (readonly) public thread, which however inspired me to start some work on it. If you think we can publish it there to let our community know what's going on, please feel free.

    I wasn't sure whether or not I should post it here already, but there are so many conceptual design decisions to make, that I don't want to make them alone. I am by no means a web developer and I am absolutely sure that I did not think about countless usecases making it necessary to refactor everything and in particular the interfaces I defined from the ground. Therefore I would like to discuss the concepts here, put all the missing features together and make sure that this extension develops the MP2 way: Think about the concepts first and build a solid base, which can be extended later by many features without running into conceptual limitations. This approach takes much longer (which is IMO one of the reasons why MP2 took so long), but the result is much better.

    So if you have any comments, remarks or even if you just want to say "It doesn't work like this because...", please feel free. I really appreciate any comment. And as usual: helping hands are of course also welcome :D I will continue to develop this extension, but don't hold your breath - it will take a lot of time...

    Enough talking - what do we have here: Attached are the binaries and the source of three plugins (binaries should work with current dev and latest Alpha 2):
    • ASPNETWebStack
    • MPAnywhere
    • MPAnywhere.EditMediaItems
    If you want to test is, just stop your MP2 server, put all three plugins into your MP2 server's plugin directory and start the server and you see: Nothing ;) But if everything went well, your MP2 server now provides a web interface and a web service... Let's go into details:

    ASPNETWebStack
    As proposed in the other thread, I used a self hosted ASP.NET web stack, which is provided by the ASPNETWebStack service. This seems to be the most powerful option and we can later on for the webservice still choose between Web API and OData for example. I decided to put this into a separate plugin and publish the service in our ServiceRegistration so that other plugins (and maybe the core) can make use of it. Unlike e.g. MPExtended with WebMediaPortal (which I really love btw.) we don't need any IIS or similar. It's all contained in the plugin.

    The ASPNETWebStackService implements quite a simple interface:
    Code:
      public interface IASPNETWebStackService
      {
    bool RegisterServer(HttpSelfHostConfiguration config);
    bool UnregisterServer(int port);
    void Shutdown();
      }

    A client plugin making use of the ASPNETWebStackService has to fill a HttpSelfHostConfiguration object with all the necessry information (mainly the URI to listen on, optionally paths for the webservice and handlers for http-requests, etc.) and call RegisterServer. That's basically it. the ASPNETWebStackService will then instantiate a HttpSelfHostServer and start it. I did not implement a wrapper around HttpSelfHostConfiguration since IMO this is too complex and would hide a lot of the power of the HttpSelfHostServer.
    It currently only allows one server per port. It seems to be possible to have multiple servers listening to different paths on one port, but this just creates possible error sources and we have 2^10 ports on every computer, which should be more than enough. If the start was successful, it returns true, otherwise false (same for all other methods returning a bool value).
    Internally, the service holds a dictionary<port, HttpSelfHostServer>. When starting a server, the port is included in the HttpSelfHostConfiguration.
    UnregisterServer needs the port as argument and then stops and disposes the respective server.
    This means that the calling plugin should hold at least the port of a server it registered. Maybe it should even hold the HttpSelfHostConfiguration to be able to modify the server later on. My finding on this is that you can modify the server when it's already running (I e.g. tried to start a server first and then add a message handler without stopping the server and it worked).
    Shutdown stops and disposes all servers which were registered with the ASPNETWebStack. It is called automatically when the system shuts down. So it wouldn't be necessary to call UnregisterServer from a plugin, which registered a server, but I would consider it best practice.
    The ASPNETWebStackService should be thread safe.
    I already have some ideas how to improve this service, but I will put the improvement ideas for all the plugins into a separate post below...

    MPAnywhere
    This is the core plugin of this extension and of course depends on the ASPNETWebService. It provides three functionalities:
    • A "virtual" http file server, which is extendable by other plugins and takes care of the device used to browse the server,
    • A basic webinterface with a menu tree (also extendable by other plugins), and
    • a very basic webservice (also extendable by other plugins)
    The Interface of the MPAnywhere service currently looks like this:
    Code:
      public interface IMPAnywhereService
      {
    bool RegisterVirtualRootPath(String virtualRootPath, MPAnywhereService.ClientType clientType);
    bool UnregisterVirtualRootPath(String virtualRootPath);
    
    bool RegisterMenuItem(String menuPath, String menuText, String viewClassName, String[] parameters);
    bool UnRegisterMenuItem(String menuPath);
    
    void Start();
    void Shutdown();
    
    HttpSelfHostConfiguration WebServiceServerConfiguration
    {
      get;
    }
      }

    Start() and Shutdown() should be self-explanatory ;)

    Virtual HTTP file server
    The virtual http file server is quite readily implemented. It is one instance of a HttpSelfHostServer with a special "VirtualFileHandler". It currently listens to port 80 on your MP2 server (will of course be configurable later on - currently hard coded so that it will only work if port 80 on your MP2 server is free, sorry for that.)
    Via RegisterVirtualRootPath other plugins can register a local file system path on the MP2 server (typically a subdirectory of the respective plugin directory), which is then available to clients via http. To do so, you also have to provide a "ClientType". I currently introduced three client types (and the respective combinations):
    Code:
     public enum ClientType
    {
      Computer,
      Tablet,
      Phone,
      Touch = Tablet | Phone,
      Any = Computer | Tablet | Phone
    }
    The reason behind that is that I think in the end we will need three client interfaces:
    • one for computers to be used with a mouse and keyboard,
    • one for tablets, such as an iPad, and
    • one for phones such as iPhone or Android devices.
    The MPAnywhereService by default registers three virtual paths:
    • [MPAnywherePluginDirectory]\wwwroot\computer\ for ClientType "Computer",
    • [MPAnywherePluginDirectory]\wwwroot\Tablet\ for ClientType "Tablet" and
    • [MPAnywherePluginDirectory]\wwwroot\Phone\ for ClientType "Phone"
    As mentioned this is all extendable by other plugins in the "MP2 everything is a plugin" spirit. Therefore the MPAnywhere.EditMediaItems plugin also registers three directories (these directories do only contain three html files currently (3x index2.html for each ClientType) - no real function. It's just to show you the concept):
    • [EditMediaItemsPluginDirectory]\wwwroot\computer\ for ClientType "Computer",
    • [EditMediaItemsPluginDirectory]\wwwroot\Tablet\ for ClientType "Tablet" and
    • [EditMediaItemsPluginDirectory]\wwwroot\Phone\ for ClientType "Phone"
    Now how does this all work. Let's assume you have an iPad and navigate to http://MP2ServerName/index2.html
    The MPAnywhereService will now search for a file called index2.html in its (virtual) root directory. Why is it virtual? Because there is no real "root directory", there is a virtual root directory consisting of (currently) six "layers". In our case, it will start with [MPAnywherePluginDirectory]\wwwroot\computer\ but will realize that the iPad is not a "Computer", but a "Tablet", so this directory is not visible to the iPad. Then it checks [MPAnywherePluginDirectory]\wwwroot\Tablet\. This directory is visible for the iPad, because it has been registered for the ClientType "Tablet". But there is no file called index2.html in this local directory, there is only index.html. So we continue to search until we find [EditMediaItemsPluginDirectory]\wwwroot\Tablet\. There is a file called index2.html and so this file is delivered to the iPad-client.
    Only if the MPAnywhereService does not find the requested file in any registered root directory (or subdirectory of course if the client specifies this subdirectory in the URI), which is visible to the specific client, it returns a file not found response.
    Please note that the device detection is nearly not implemented, yet. It just detects if you are using an iPad and then directs you to the virtual directory for tablets. With any other device you are currently treated as a "Computer". I think we need some external library for this to work reliable later...
    The example just mentioned is by the way real - if you have an iPad, browse to http://MP2ServerName/index2.html. Then do the same with any other device and you will see the little difference...
    UnregisterVirtualRootPath should be self explaining - use it if your plugin does not want its directories be part of the virtual root directory anymore. The files will just disappear from our MPAnywhere web file server.

    Webinterface with MenuTree
    Now we are getting in a region, where the implementation is anything but complete...
    The idea is that we have three webinterfaces:
    • One for computers, which I will implement with Sencha extjs (this one you can already see)
    • One for tablets, which I'll probably implement with Sencha Touch (not implemented at all, yet) and
    • One for phones with a touch interface (also not implemented, yet). I think we can also use Sencha Touch for this and reuse many of the components from the tablet interface. But an iPhone's display is just not big enough to display a menu and the application at the same time.
    (Now you can also see why you can register a root path for e.g. Phone and Tablet. I would later on do so for the sencha Touch files, which are then visible automatically to both kinds of clients)

    The interface for computers and tablets shall be structured with three simple panels. One panel at the top with some basic information on the system, one menu panel on the left (as a treeview for computers and maybe something like the iPad's mail app on the left side for tablets) and a "main application tab" in the (right) center. For phones we should probably omit the top panel and display the menu full screen until the user starts an "application", which is then also displayed fullscreen.

    For computers you can already see what I mean by just browsing to http://MP2ServerName. It should look something like this:
    MPAnywhere Webinterface for Computers.jpg
    (Now it's clear that I'm not a designer when you look at the top panel - as mentioned, any help is appreciated :D )

    Currently, the menu entries are hard coded. But the idea is that the MPAnywhereService provides the menu tree dynamically via a webservice. This also makes clear what the RegisterMenuItem and UnregisterMenuItem methods are for. Other MP2 plugins can register menu items which will then automatically be provided via the webservice and displayed automatically in the menu tree. The parameters of these methods are just first ideas. I'm not yet happy with them, since I still need to think about how to store the tree in the server.
    The menuPath parameter says where in the menu tree this menu items shall be displayed. The menuText is the text that is displayed in the menu at the given path.
    Then you have to specify the viewClassName of your "application". This class must be derived from the extjs TabPanel class and your plugin must provide the respective js-file in the right place via the VirtualDirectory. It is then automatically loaded and shown in the main application panel when the user clicks on the respective menu item in the menu tree. The automatic loading of the class files already works from the extjs side. If you e.g. click on "Some Cool Extension", the TabPanel on the right is provided by the EditMediaItems plugin - not the MPAnywhere plugin. Fancy, isn't it ;) However, as mentioned, the menu tree (including the viewClassName) is not yet provided by a webapi. The class names are currently hard coded in the js-code.
    Finally, there is a parameter called "parameters". The idea behind it is the following: Let's assume we later have a plugin providing access to our MP2 server's settings. We would probably include the settings tree of MP2 as a sub-menu tree below the node "MP2 Server Settings" in our menu tree on the left. Now we probably don't want to provide a separate TabPanel for every node in the settings tree of our MP2 server, but we want to provide a generic TabPanel which is called with some parameters that tell the panel, which settings to display. Therefore the viewClassName would be the same for every leaf-node below "MP2 Server Settings", but our TabPanel class would be able to determine what settings to display by fetching the parameters stored in the menu tree for the selected node.
    As mentioned, these parameters are not yet as I want them to be - they are intended only to explain what my idea behind it is...

    WebService
    The MPAnywhereService also registers a second HttpSelfHostServer (currently hardcoded on port 81 - again sorry, this will be configurable later). At this point, it becomes clear that this is really only a proof of concept. MPAnywhereService does not provide any webservice, yet.

    It just maps a http route for testing purposes "http://MP2ServerName:81/api/{Controller}/{id}", which is obviously a WebApi route. I'm not decided at all, yet, whether we shall use WebApi or OData. WebApi seems to be easier to implement, but you have to write many methods like GetMediaItemsByMediaCategory, GetMediaItemsByID, GetMediaItemsByName, etc. whereas with OData you can send queries to a single provider method, which then evaluates the query and returns the requested MediaItems. But on the other hand, OData would require a lot more work on the server side. This will in the end be a try and error process. Let's see what suits us best in the end.
    Also the fact that I currently start a second HttpSelfHostServer for the WebService is not a final decision, yet (the same applies to everything I mention here...). Starting the first HttpSelfHostServer takes about 0.4 seconds on my old Laptop in a virtual machine. Starting this second one takes about 0.07 seconds, so I think it is not really having two completely separate instances but the second and further ones use the resources together with the first instance. The overhead seems to be minimal. But we can also reserve the "/api/" and maybe the "/OData/" paths from our web file server (already tested, requires only minimal changes). But I wanted to keep these two things separate in the beginning to easier determine possible bugs. In the end, it may be too complicated on the js side to have the webservice listening on a different port of the server. While you can easily address e.g. "../../api/MediaItems" in a js file when the file as well as the webservice is available via the same server port, the js file cannot know the URI of the webservice if it is on another port. So we would have to provide a dynamically created file on our web file server containing information on where the js file can reach the webservice. Shouldn't be too complicated, but I don't know whether it's worth the effort...

    Now why am I providing a webservice without any controllers, yet? Well, the concept I wanted to prove is that you can provide a WebApi controller from a different plugin. In this case the MPAnywhere.EditMediaItems plugin. Besides registering the three VirtualRootPaths above, it also provide an APIController for MediaItems. PLEASE NOTE: This is definitely not the final controller API and the data is just dummy data without any connection to the MediaLibrary. There is still a long way to go until this will be the case (And sorry, Lehmden, if this made you hope too early - the plugin is already called EditMediaItems, because this was your intention in the other thread. But as you can see, this is not (yet) possible, but I'm sure it will be possible...). I just wanted to make sure that our MPAnywhere webservice is extendable by other MP2 plugins - which it is. It works because our PluginManager loads the assemblies of all plugins which are set to AutoActivate in the plugin.xml at the startup of the MP2 server. So if you want to provide API-Controllers via additional plugins, make sure you set AutoActivate to true.
    If you want to test the WebApi, you can do so by e.g. browsing to:
    http://Mp2ServerName:81/api/MediaItems
    http://Mp2ServerName:81/api/MediaItems/2 or e.g.
    http://Mp2ServerName:81/api/MediaItems?category=pictures
    When you do so with FireFox, you will immediately see the objects in XML-format. If you use IE, it by default requests JSON-format, which is also available automatically and you are prompted to download a file called *.json - save it and open it with the editor and you will see the result.

    Finally we have the WebServiceServerConfiguration property in the MPAnywhereService. This returns the HttpSelfHostConfiguration of the webservice server to make it possible for other plugins to modify the configuration e.g. by adding additional http routes (not used, yet, because the route used by the EditMediaItems plugin is currently registered as standard route by MPAnywhere).

    MPAnywhere.EditMediaItems
    As mentioned above, this is really just a "proof of concept plugin" at the moment. It registers three virtual root paths with the MPAnywhereService's virtual web file server and provides a dummy controller for MPAnywhere's webservice server - nothing more, yet. I'm also thinking about renaming it to MPAnywhere.CoreExtensions because I think we can provide some core functionality, but the rest is open to the community (thinking about a MediaPlayer plugin, etc.). We could also integrate the core functionality directly into MPAnywhere, but to make it easier for community developers I think it is a good idea to keep this separated so that they can just copy this plugin and start modifying it.

    Ok, that's basically it for now. And I think that it is understandable now why I would really appreciate an absolutely open discussion about this. In particular, I would be very happy if this discussion is not only made by people already specializing in MP2. I still hope that there are a lot of team members having the "vision" we discussed about so often in the last months. So if you have visions don't go to the doctor (that's probably a joke only for Germans... ;) ) but post your visions here. I am willing to rewrite and rethink everything I have implemented so far to make this THE Web(Inter)face of MP2, but I need your comments, your criticism and your ideas (and a lot more time, but this is a different story...). In particular, I am completely lost on the js and extjs side. Never did any js programming before so if there is someone with deeper knowledge there, any help or hints would be greatly appreciated.

    I will reserve the next two posts for concrete improvement ideas and a change log. I have many ideas already and will post them later, just to make sure we don't forget them. And now let the discussion start!

    cheers,
    Michael
     

    Attachments

    • MP2 WebService Plugins_v0.04.zip
      4.3 MB
    Last edited:

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Changelog:

    v0.04 (current version see first post):
    • Renamed ASPNETWebStack plugin to OwinService plugin
      • Reason: We are not using HttpSelfHostServer anymore, but Owin / Katana
    • Renamed MPAnywhere plugin to MPAnywhereService plugin
      • Reason: MPAnywhere is nothing more than a service accessible through the ServiceRegistration
    • Renamed MPAnywhere.EditMediaItems plugin to MPAnywhereService.Core plugin
      • Reason: This plugin is supposed to provide the core extensions for the MPAnywhereService. One of these core extensions will be a possibility to edit MediaItems - but there is more to come...
    • Cleaned up and unified namespaces, class names, method names, etc.
    • Cleaned up the code to match the MP2 coding standards
    • Added a lot of documentation to the code to make it easier understandable for new developers ;)
    • Updated Owin/Katana and WebAPI dependencies as far as possible with .NET 4.0
    • Added Windows Authetication to the webinterface for testing purposes. When you try to access the webinterface you are prompted to enter a username and password. You can use any windows username / password combination, which is valid on your MP2 Server computer
    v0.02:
    • Hooked up the MPAnywhere.EditMediaItems plugin's WebApi to the MediaLibrary so that it actually returns MediaItems from the MediaLibrary
    • Implemented an ITraceWriter, which logs into the MP2-Logger. This enables us to trace what's going on inside of the WebApi
    • Implemented a MediaItemJsonConverter and a MediaItemAspectJsonConverter. These make sure that we get our MediaItems and MediaItemAspects in a nice and clean Json form.
    v0.01:
    • First published version.
    • Consists of three plugins: ASPNETWebStack, MPAnywhere and MPAnywhere.EditMediaItems
     
    Last edited:

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    This is a list of improvement ideas and open questions. I will update this list from other posts in this thread:

    General
    • extjs is only available as an outdated version (4.1.1, current is 4.2.1) as nuget package: http://www.nuget.org/packages/extjs/ This really bugs me because the download is over 70MB and I really don't want to include all that stuff in our source code. I only included the absolutely necessary files atm, but this is the most part of the size of the source and bin directories of the plugins. We should add this to our MP nuget feed - extjs is plublished under GPLv3 so this should be allowed.
    • Tranlsation: For the menu items we can use the inbuilt localization service of MP2. But what about all the js-files? Shall we parse these and use the MP2 localization service before serving them to clients (might be slow...) or shall we make use of sencha's localization services in extjs and touch?
    • ATM we cannot follow sencha's way of deploying an application according to the docs. To my understanding this would break the possibility to extent our webinterface by MP2 plugins, but maybe I haven't understood completely, yet, what happens in this deployment process. Currently we need the possibility that other MP2 plugins can provide js-files in the virtual directory, which are then automatically loaded at runtime by the webinterface. Is this also possible when we "compile" our sencha js-files (or whatever happens during that process...)?
    • As FreakyJ pointed out we need a concept to stream media. We will use the MPExtended streaming API for that.
    OwinService
    • To comply with our MP2 principle of "just use the plugin and it works", we should determine whether a given port on the server is free or not. If it is not free, we should chose another port and start the server anyway. We then note this in the logs and if a user can't reach his webinterface we can easily tell him how to reach it (provided we get a bug report with logs ;) ).
      • Whether a port is free or not can only be determined via Try/Catch.
      • This functionality should be optional since other plugins may require a certain port and if it's not free, it's better for them not to start the Owin App at all.
    MPAnywhereService / Virtual File Server
    • Switch from own implementation to Owin/Katana's StaticFiles extension
    • Implement different webinterfaces for different ClientTypes by way of redirection
    • Provide WebAPI and Static Files on the same port to avoid Same Origin Policy problems and the need for CORS.
    • We need some kind of authorization - probably with username and password. What are the ideas about user rights management? Is it sufficient to have admin users with full access and other users with restricted access (no access to settings, only read access to MediaItems, etc.) or should we integrate it with the MP2 user service (to the extent this is already implemented...)
      • Since v0.04 we have an implementation of a Windows Authorization for testing purposes. When you are trying to access the webinterface you are prompted to enter username and password. Just enter any valid Windows username / password combination you have on your MP2 Server computer.
    MPAnywhereService / MenuTree
    • We still need a class system to hold the menu tree in the MP2 server. Is there already something like that in MP2? I already had a look to the settings tree implementation, but this seems to be really tailor made for settings and has too much unnecessary overhead for a simple menu tree...
    MPAnywhereService / WebService
    • Well, everything still open here - need to do further try and error... Any comment welcome!
    • I think we should only provide one webservice in this plugin, which provides the menu tree. All the other webservices should be provided by plugins. Comments to this idea?
    • Authentication will be handled the same way as for static files using Owin/Katana's Authorization possibilities
    • Add SignalR as another WebService.
    • Once we have switched to .NET 4.5 (or .NET 4.5.1) we should use attribute based routing
    MPAnywhereService.Core
    • Shall we expose our MediaItem objects directly or provide a wrapper class? In our MediaItems the data (i.e. the MediaItemAspectProperties) is quite deeply burried in a list of MediaItemAspects, which then hold the MediaItemsAspectProperties in a map. On the one hand, these are quite complicated objects and I'm not sure how Web Api can handle them. It would require some coding to re-map them on the js side. On the other hand we have them already and they contain all the information we need...
     
    Last edited:

    chefkoch

    Retired Team Member
  • Premium Supporter
  • October 5, 2004
    3,129
    1,634
    Dresden / Munich / Maastricht
    Home Country
    Germany Germany
    I need a tag cloud @high
    Just to proof "extendable" is word I read the most in this post.

    Very interesting, and great work so far :) (y)
    Even I am not known to webdev and all the networking that much so I might do not understand everything.

    And as always, I think with public discussion we have a huge chance to attract new developers. Not sure if might loose any "surprises" and ideas to our competitors this way, but gaining only one motivated and/or experienced devs would be worth imo, but that is all up to you as you are the thread starter ;)

    Thanks again for focusing on this (y)
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Well I'm not a webdev either, so I probably don't really understand many of the things I explained above ;)
    I completely agree with making this public at some time because we urgently need a real webdev for this. I'll continue to read on extjs and sencha touch, but I doubt I will be able to become really familiar with it. Compared to pure js it is somewhat like "object oriented", which makes it a bit easier for me. But the syntax still feels strange to me...
    But let's first discuss this a little bit internally to make sure that we really get a discussion going. If this is the case, let's make it public...
     

    FreakyJ

    Retired Team Member
  • Premium Supporter
  • July 25, 2010
    4,024
    1,420
    Home Country
    Germany Germany
    Great work! I will give it a go later ;)

    But I have one more question, maybe you wrote it already and I didn't got it :p
    If I want to implement a streaming plugin e.g like MPExtended:
    can I create file paths like http://MP2Server:PORT/streaming/id/1235 which is called by a flash player to receive a stream? So basically this url should tell a plugin to start transcoding a video and output it on this address so that the flash player can retrieve it.
    Because as I understood your explanations above it is only possible to call static content or retrieve objects by the webapi. I think streaming is an important point to keep in mind here :)
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    Yep, should be possible without a Problem from what I read so far.
    The stream would probably be available on another port of the Server in the end, but starting the stream would work with a call as you describe it above. But don't Forget: we don't have a transcoding plugin for MP2, yet (that would probably be the fourth plugin I have in mind...) so what we could do currently is just open the files and stream them as they are as a Response to the http-get-request.
    BTW: I wouldn't use Flash since this doesn't work on any IDevice. I would much more prefer transcoding to mp4 for Videos and mp3 for Music. That way we can use html5 to Display it.
    Sencha Touch has a Music and Video Player inbuilt (working on nearly all devices supporting html5). For extjs this is unfortunately not the case. But this one Looks quite promising: www.projekktor.com I just don't have an idea whether it wodks together with extjs, yet :)
    Thanks for the comments - much appreciated!
     

    FreakyJ

    Retired Team Member
  • Premium Supporter
  • July 25, 2010
    4,024
    1,420
    Home Country
    Germany Germany
    I installed your plugin and gave it a test :)
    Pretty nice what you build already ;) MP2 gets really strong!
    I'm not sure if the navigation concept is the right one, but to be honest I can't come up with a better one... Is it possible to replace the menu easily?
    Lets say if a webdev would like to have a top bar instead a side menu?

    And If you really implement the most stuff in js it would be nice to have a rootPath which serves the js files which do the magic so that it hasn't to be included in every device root folder. Maybe an example. Something like this:


    • [server]/tablet/[files]
    • [server]/desktop/[files]
    • [server]/common/[files used by all devices like pictures etc]

    And maybe you aready planned it, but maybe it would be nice to do as much as possible on the server side, so that you just have to call some urls like:
    [server]/mediaLibrara/set/title/TEST/id/45345
    where title and id are variables followed by their value. or:
    [server]/mediaLibrara/delete/id/4545
    But somehow I have the feeling that this was already the plan :p
    Sorry for bringing up some stupid things, but I try to think about it and this are the questions which came to my mind first :)
     

    MJGraf

    Retired Team Member
  • Premium Supporter
  • January 13, 2006
    2,478
    1,385
    First of all thanks a lot for testing, FreakyJ!
    And to say it clear: nothing brought up in this thread is stupid. Every comment is helpful and I will try to explain my thoughts to every part of this, which does not mean my thoughts are right ;)

    I'm not sure if the navigation concept is the right one, but to be honest I can't come up with a better one... Is it possible to replace the menu easily? Lets say if a webdev would like to have a top bar instead a side menu?

    Well, that's one of the reasons for this thread. I'm not a designer and it's really hard for me to come up with new design ideas. The background why I used this layout is in particular:
    • It's quite common and people are used to it.
    • I want to have a similar layout for phones, tablets and computers to make it as intuitive as possible. No matter whether you use your iPad, iPhone, Android Phone or a desktop, you always find what you need. Of course the menu has to be a little bit different for touch devices and for desktop pcs, but you can always have the same menu tree and feel like "at home".
    • The reason I chose a tree on the left is that it is the most flexible layout IMO. We could also make it look like a desktop, but then you have only one icon per "application plugin" and I'm not sure how we would implement this on touch devices. Or take e.g. a toolbar: http://docs.sencha.com/extjs/4.2.1/#!/example/toolbar/toolbars.html looks extremely cool as well, but I don't know how this "feels" on a touch device...
    Back to your question: No, you cannot "replace" the tree menu. But we can easily make the "main tree menu" hideable (same for the top panel). The plugin developer then has the whole main panel for his application plugin. And there it is also possible to add further menus, etc. So, although the developer of a plugin cannot "replace" the tree menu, it is easily possible to add an additional top bar menu in the main panel.

    And If you really implement the most stuff in js it would be nice to have a rootPath which serves the js files which do the magic so that it hasn't to be included in every device root folder. Maybe an example. Something like this:

    Well that's the easiest task. That's just creating a "common" folder and adding one line of code. But maybe my explanation above wasn't that clear what the Virtual File System is able to do. Let me give you a further example:

    Let's assume a plugin registers the following local path on the server as virtual path just for ClientType "Computer":
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\FirstPlugin\wwwroot\Computer\
    In this path you have the following files / folders:
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\FirstPlugin\wwwroot\Computer\java1.js
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\FirstPlugin\wwwroot\Computer\subfolder\java2.js

    Then we have a second plugin registering the following local path on the server as virtual path for all ClientTypes:
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\SecondPlugin\wwwroot\Common\
    In this path you have the following files / folders:
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\SecondPlugin\wwwroot\Common\Pictures\Pic1.jpg
    C:\Program Files (x86)\Team Mediaportal\MP2 Client\plugins\SecondPlugin\wwwroot\Common\java3.js

    Now let's assume you use a computer for browsing. What you can "see" and access is the following:
    http://MP2ServerName/java1.js
    http://MP2ServerName/java3.js
    http://MP2ServerName/subfolder/java2.js
    http://MP2ServerName/pictures/Pic1.jpg

    When you use an iPad instead of a computer, you can see and browse the following files:
    http://MP2ServerName/java3.js
    http://MP2ServerName/pictures/Pic1.jpg
    The other files are hidden.

    This means you only have to have multiple files for multiple devices if the files are different. If they are the same, you only need them physically once on the server. But your observation is right, I didn't implement a "common" directory, yet. Only the specific ones for computers, tablets and phones. But the combined ones will follow. If I e.g. implement Sencha touch, we would need this library for both, tablets and phones. So I would probably make a wwwroot\touch folder and register it for tablets and phones.

    You can easily test this if you have the plugins installed. Just copy a file of your choice in your [...]plugins\wwwroot\computer\ directory and it will be available if you browse to http://[MP2ServerName]/[filename].[ext]. Copy a different file with the same name to \wwwroot\tablet and it will not be visible for a computer. But when you use an iPad and browse to http://[MP2ServerName]/[filename].[ext] you will get the different file with the same name. Hope this makes it a little clearer...

    And maybe you aready planned it, but maybe it would be nice to do as much as possible on the server side, so that you just have to call some urls like: [server]/mediaLibrara/set/title/TEST/id/45345 where title and id are variables followed by their value. or: [server]/mediaLibrara/delete/id/4545

    Well, in any case something along these lines. But what we have to take into account for this particular webservice is that we have MediaItems. A MediaItem may be a music file, a video, a movie a series or a picture. This means that not every MediaItem has e.g. a MovieAspect. This exists only for movies of course and the AudioAspect only exists for music files. What I could imagine is something like

    Code:
    http://MP2ServerName:81/api/MediaItems/[MediaItemID]&AspectName=AudioAspect&PropertyName=AlbumArtist&Value=Queen

    But there are two downsides in this idea (maybe more, if you see them, please post ;) ):
    • Let's assume we really have a cool application to edit MediaItemAspects. When the user makes a lot of changes, we have to make a lot of webservice calls - one call for every property. This may be a performance problem. It would be faster to have the complete MediaItems object on the client side, change its values and transfer it back to the server (in the http request body instead of in the URI) in one call.
    • If we have complex types such as pictures in our MediaItems (thinking of the ThumbnailLargeAspect) it won't be possible to include the data in the URI. In that case we have to transfer the data in the message body.
    Again, these are just thoughts for now - maybe we already have found an ideal solution, but we still need a lot more try and error... In any case this implementation has the advantage that the API is very easy and you can even call the method with a browser, which is not possible as soon as we need data in the message body.

    Thanks again for sharing your thoughts!
    Michael
     
    Last edited:

    FreakyJ

    Retired Team Member
  • Premium Supporter
  • July 25, 2010
    4,024
    1,420
    Home Country
    Germany Germany
    thanks for clarifying that all makes perfectly sense to me :)
    And with the first two answers I'm pretty happy^^

    Some thoughts regarding the Mdeiaitems, I'm curious what you think about that ;)




    this looks pretty good to me ;)

    Let's assume we really have a cool application to edit MediaItemAspects. When the user makes a lot of changes, we have to make a lot of webservice calls - one call for every property.

    maybe we could batch it? so that we have a separator in the URI? e.g


    note that I added two times a property with the element ID 0. I haven't thought long about this idea, maybe it has some big disadvantages, but I wanted to write it down before I go to bead and it is lost :p

    Is there a size limit for urls?

    In any case this implementation has the advantage that the API is very easy and you can even call the method with a browser, which is not possible as soon as we need data in the message body.

    maybe there is a more elegant way, but maybe one of this options maybe be suitable for pictures:
    1. use base64 and transport it within the url. But that might be not the ideal solution, because the url isn't made for such stuff^^
    2. we could have a global upload address like http://MP2Server/upload/ which places all files in a central upload directory and create a unique file name for each file. This unique file name is passed in the url query and the backend gets the file from the central upload directory. Here it would be important that the file is already uploaded before we are sending the request. And maybe we should keep track of the files and delete them if they are older than 24h.
    3. don't use the url for datamanipulation and make everything with post commands. This would have the disadvantage that other applications can't use the api so easily...
     
    Status
    Not open for further replies.

    Users who are viewing this thread

    Top Bottom