using System; using System.Collections.Generic; using System.Linq; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Services; using Emby.Server.Implementations.HttpServer; namespace Emby.Server.Implementations.Services { [Route("/swagger", "GET", Summary = "Gets the swagger specifications")] [Route("/swagger.json", "GET", Summary = "Gets the swagger specifications")] public class GetSwaggerSpec : IReturn { } public class SwaggerSpec { public string swagger { get; set; } public string[] schemes { get; set; } public SwaggerInfo info { get; set; } public string host { get; set; } public string basePath { get; set; } public SwaggerTag[] tags { get; set; } public IDictionary> paths { get; set; } public Dictionary definitions { get; set; } public SwaggerComponents components { get; set; } } public class SwaggerComponents { public Dictionary securitySchemes { get; set; } } public class SwaggerSecurityScheme { public string name { get; set; } public string type { get; set; } public string @in { get; set; } } public class SwaggerInfo { public string description { get; set; } public string version { get; set; } public string title { get; set; } public string termsOfService { get; set; } public SwaggerConcactInfo contact { get; set; } } public class SwaggerConcactInfo { public string email { get; set; } public string name { get; set; } public string url { get; set; } } public class SwaggerTag { public string description { get; set; } public string name { get; set; } } public class SwaggerMethod { public string summary { get; set; } public string description { get; set; } public string[] tags { get; set; } public string operationId { get; set; } public string[] consumes { get; set; } public string[] produces { get; set; } public SwaggerParam[] parameters { get; set; } public Dictionary responses { get; set; } public Dictionary[] security { get; set; } } public class SwaggerParam { public string @in { get; set; } public string name { get; set; } public string description { get; set; } public bool required { get; set; } public string type { get; set; } public string collectionFormat { get; set; } } public class SwaggerResponse { public string description { get; set; } // ex. "$ref":"#/definitions/Pet" public Dictionary schema { get; set; } } public class SwaggerDefinition { public string type { get; set; } public Dictionary properties { get; set; } } public class SwaggerProperty { public string type { get; set; } public string format { get; set; } public string description { get; set; } public string[] @enum { get; set; } public string @default { get; set; } } public class SwaggerService : IService, IRequiresRequest { private readonly IHttpServer _httpServer; private SwaggerSpec _spec; public IRequest Request { get; set; } public SwaggerService(IHttpServer httpServer) { _httpServer = httpServer; } public object Get(GetSwaggerSpec request) { return _spec ?? (_spec = GetSpec()); } private SwaggerSpec GetSpec() { string host = null; Uri uri; if (Uri.TryCreate(Request.RawUrl, UriKind.Absolute, out uri)) { host = uri.Host; } var securitySchemes = new Dictionary(); securitySchemes["api_key"] = new SwaggerSecurityScheme { name = "api_key", type = "apiKey", @in = "query" }; var spec = new SwaggerSpec { schemes = new[] { "http" }, tags = GetTags(), swagger = "2.0", info = new SwaggerInfo { title = "Jellyfin Server API", version = "1.0.0", description = "Explore the Jellyfin Server API", contact = new SwaggerConcactInfo { name = "Jellyfin Community", url = "https://jellyfin.readthedocs.io/en/latest/user-docs/getting-help/" } }, paths = GetPaths(), definitions = GetDefinitions(), basePath = "/jellyfin", host = host, components = new SwaggerComponents { securitySchemes = securitySchemes } }; return spec; } private SwaggerTag[] GetTags() { return Array.Empty(); } private Dictionary GetDefinitions() { return new Dictionary(); } private IDictionary> GetPaths() { var paths = new SortedDictionary>(); // REVIEW: this can be done better var all = ((HttpListenerHost)_httpServer).ServiceController.RestPathMap.OrderBy(i => i.Key, StringComparer.OrdinalIgnoreCase).ToList(); foreach (var current in all) { foreach (var info in current.Value) { if (info.IsHidden) { continue; } if (info.Path.StartsWith("/mediabrowser", StringComparison.OrdinalIgnoreCase) || info.Path.StartsWith("/jellyfin", StringComparison.OrdinalIgnoreCase)) { continue; } paths[info.Path] = GetPathInfo(info); } } return paths; } private Dictionary GetPathInfo(RestPath info) { var result = new Dictionary(); foreach (var verb in info.Verbs) { var responses = new Dictionary { { "200", new SwaggerResponse { description = "OK" } } }; var apiKeySecurity = new Dictionary { { "api_key", Array.Empty() } }; result[verb.ToLowerInvariant()] = new SwaggerMethod { summary = info.Summary, description = info.Description, produces = new[] { "application/json" }, consumes = new[] { "application/json" }, operationId = info.RequestType.Name, tags = Array.Empty(), parameters = Array.Empty(), responses = responses, security = new [] { apiKeySecurity } }; } return result; } } }