TransportCommands.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Xml.Linq;
  5. using Emby.Dlna.Common;
  6. using Emby.Dlna.Ssdp;
  7. namespace Emby.Dlna.PlayTo
  8. {
  9. public class TransportCommands
  10. {
  11. private List<StateVariable> _stateVariables = new List<StateVariable>();
  12. public List<StateVariable> StateVariables
  13. {
  14. get => _stateVariables;
  15. set => _stateVariables = value;
  16. }
  17. private List<ServiceAction> _serviceActions = new List<ServiceAction>();
  18. public List<ServiceAction> ServiceActions
  19. {
  20. get => _serviceActions;
  21. set => _serviceActions = value;
  22. }
  23. public static TransportCommands Create(XDocument document)
  24. {
  25. var command = new TransportCommands();
  26. var actionList = document.Descendants(uPnpNamespaces.svc + "actionList");
  27. foreach (var container in actionList.Descendants(uPnpNamespaces.svc + "action"))
  28. {
  29. command.ServiceActions.Add(ServiceActionFromXml(container));
  30. }
  31. var stateValues = document.Descendants(uPnpNamespaces.ServiceStateTable).FirstOrDefault();
  32. if (stateValues != null)
  33. {
  34. foreach (var container in stateValues.Elements(uPnpNamespaces.svc + "stateVariable"))
  35. {
  36. command.StateVariables.Add(FromXml(container));
  37. }
  38. }
  39. return command;
  40. }
  41. private static ServiceAction ServiceActionFromXml(XElement container)
  42. {
  43. var argumentList = new List<Argument>();
  44. foreach (var arg in container.Descendants(uPnpNamespaces.svc + "argument"))
  45. {
  46. argumentList.Add(ArgumentFromXml(arg));
  47. }
  48. return new ServiceAction
  49. {
  50. Name = container.GetValue(uPnpNamespaces.svc + "name"),
  51. ArgumentList = argumentList
  52. };
  53. }
  54. private static Argument ArgumentFromXml(XElement container)
  55. {
  56. if (container == null)
  57. {
  58. throw new ArgumentNullException(nameof(container));
  59. }
  60. return new Argument
  61. {
  62. Name = container.GetValue(uPnpNamespaces.svc + "name"),
  63. Direction = container.GetValue(uPnpNamespaces.svc + "direction"),
  64. RelatedStateVariable = container.GetValue(uPnpNamespaces.svc + "relatedStateVariable")
  65. };
  66. }
  67. private static StateVariable FromXml(XElement container)
  68. {
  69. var allowedValues = new List<string>();
  70. var element = container.Descendants(uPnpNamespaces.svc + "allowedValueList")
  71. .FirstOrDefault();
  72. if (element != null)
  73. {
  74. var values = element.Descendants(uPnpNamespaces.svc + "allowedValue");
  75. allowedValues.AddRange(values.Select(child => child.Value));
  76. }
  77. return new StateVariable
  78. {
  79. Name = container.GetValue(uPnpNamespaces.svc + "name"),
  80. DataType = container.GetValue(uPnpNamespaces.svc + "dataType"),
  81. AllowedValues = allowedValues.ToArray()
  82. };
  83. }
  84. public string BuildPost(ServiceAction action, string xmlNamespace)
  85. {
  86. var stateString = string.Empty;
  87. foreach (var arg in action.ArgumentList)
  88. {
  89. if (arg.Direction == "out")
  90. {
  91. continue;
  92. }
  93. if (arg.Name == "InstanceID")
  94. {
  95. stateString += BuildArgumentXml(arg, "0");
  96. }
  97. else
  98. {
  99. stateString += BuildArgumentXml(arg, null);
  100. }
  101. }
  102. return string.Format(CommandBase, action.Name, xmlNamespace, stateString);
  103. }
  104. public string BuildPost(ServiceAction action, string xmlNamesapce, object value, string commandParameter = "")
  105. {
  106. var stateString = string.Empty;
  107. foreach (var arg in action.ArgumentList)
  108. {
  109. if (arg.Direction == "out")
  110. {
  111. continue;
  112. }
  113. if (arg.Name == "InstanceID")
  114. {
  115. stateString += BuildArgumentXml(arg, "0");
  116. }
  117. else
  118. {
  119. stateString += BuildArgumentXml(arg, value.ToString(), commandParameter);
  120. }
  121. }
  122. return string.Format(CommandBase, action.Name, xmlNamesapce, stateString);
  123. }
  124. public string BuildPost(ServiceAction action, string xmlNamesapce, object value, Dictionary<string, string> dictionary)
  125. {
  126. var stateString = string.Empty;
  127. foreach (var arg in action.ArgumentList)
  128. {
  129. if (arg.Name == "InstanceID")
  130. {
  131. stateString += BuildArgumentXml(arg, "0");
  132. }
  133. else if (dictionary.ContainsKey(arg.Name))
  134. {
  135. stateString += BuildArgumentXml(arg, dictionary[arg.Name]);
  136. }
  137. else
  138. {
  139. stateString += BuildArgumentXml(arg, value.ToString());
  140. }
  141. }
  142. return string.Format(CommandBase, action.Name, xmlNamesapce, stateString);
  143. }
  144. private string BuildArgumentXml(Argument argument, string value, string commandParameter = "")
  145. {
  146. var state = StateVariables.FirstOrDefault(a => string.Equals(a.Name, argument.RelatedStateVariable, StringComparison.OrdinalIgnoreCase));
  147. if (state != null)
  148. {
  149. var sendValue = state.AllowedValues.FirstOrDefault(a => string.Equals(a, commandParameter, StringComparison.OrdinalIgnoreCase)) ??
  150. state.AllowedValues.FirstOrDefault() ??
  151. value;
  152. return string.Format("<{0} xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"{1}\">{2}</{0}>", argument.Name, state.DataType ?? "string", sendValue);
  153. }
  154. return string.Format("<{0}>{1}</{0}>", argument.Name, value);
  155. }
  156. private const string CommandBase = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" + "<SOAP-ENV:Body>" + "<m:{0} xmlns:m=\"{1}\">" + "{2}" + "</m:{0}>" + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
  157. }
  158. }