Explorar o código

Merge pull request #1 from jellyfin/master

Pull latest to my fork
Peter Maar %!s(int64=5) %!d(string=hai) anos
pai
achega
adbf375efe
Modificáronse 100 ficheiros con 771 adicións e 719 borrados
  1. 1 1
      .ci/azure-pipelines-main.yml
  2. 1 1
      .ci/azure-pipelines-windows.yml
  3. 13 7
      .github/ISSUE_TEMPLATE/bug_report.md
  4. 120 25
      CONTRIBUTORS.md
  5. 18 4
      Dockerfile
  6. 35 4
      Dockerfile.arm
  7. 24 4
      Dockerfile.arm64
  8. 2 0
      Emby.Dlna/Api/DlnaServerService.cs
  9. 2 0
      Emby.Dlna/Api/DlnaService.cs
  10. 1 0
      Emby.Dlna/Common/Argument.cs
  11. 9 1
      Emby.Dlna/Common/DeviceIcon.cs
  12. 3 3
      Emby.Dlna/Common/DeviceService.cs
  13. 8 5
      Emby.Dlna/Common/ServiceAction.cs
  14. 9 8
      Emby.Dlna/Common/StateVariable.cs
  15. 17 9
      Emby.Dlna/Configuration/DlnaOptions.cs
  16. 2 0
      Emby.Dlna/ConfigurationExtension.cs
  17. 7 1
      Emby.Dlna/ConnectionManager/ConnectionManager.cs
  18. 2 0
      Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
  19. 16 14
      Emby.Dlna/ConnectionManager/ControlHandler.cs
  20. 2 0
      Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs
  21. 3 1
      Emby.Dlna/ContentDirectory/ContentDirectory.cs
  22. 2 0
      Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
  23. 181 183
      Emby.Dlna/ContentDirectory/ControlHandler.cs
  24. 2 0
      Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs
  25. 2 0
      Emby.Dlna/ControlRequest.cs
  26. 7 5
      Emby.Dlna/ControlResponse.cs
  27. 3 2
      Emby.Dlna/Didl/DidlBuilder.cs
  28. 2 0
      Emby.Dlna/Didl/Filter.cs
  29. 2 0
      Emby.Dlna/Didl/StringWriterWithEncoding.cs
  30. 2 0
      Emby.Dlna/DlnaManager.cs
  31. 13 0
      Emby.Dlna/Emby.Dlna.csproj
  32. 8 5
      Emby.Dlna/EventSubscriptionResponse.cs
  33. 4 1
      Emby.Dlna/Eventing/EventManager.cs
  34. 4 2
      Emby.Dlna/Eventing/EventSubscription.cs
  35. 1 0
      Emby.Dlna/IConnectionManager.cs
  36. 1 0
      Emby.Dlna/IContentDirectory.cs
  37. 1 0
      Emby.Dlna/IEventManager.cs
  38. 1 0
      Emby.Dlna/IMediaReceiverRegistrar.cs
  39. 2 0
      Emby.Dlna/IUpnpService.cs
  40. 16 5
      Emby.Dlna/Main/DlnaEntryPoint.cs
  41. 22 21
      Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs
  42. 6 1
      Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs
  43. 2 0
      Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
  44. 2 0
      Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
  45. 17 15
      Emby.Dlna/PlayTo/Device.cs
  46. 2 0
      Emby.Dlna/PlayTo/DeviceInfo.cs
  47. 2 1
      Emby.Dlna/PlayTo/PlayToController.cs
  48. 6 4
      Emby.Dlna/PlayTo/PlayToManager.cs
  49. 2 0
      Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs
  50. 2 0
      Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs
  51. 2 0
      Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
  52. 2 0
      Emby.Dlna/PlayTo/PlaylistItem.cs
  53. 2 1
      Emby.Dlna/PlayTo/PlaylistItemFactory.cs
  54. 8 6
      Emby.Dlna/PlayTo/SsdpHttpClient.cs
  55. 2 0
      Emby.Dlna/PlayTo/TRANSPORTSTATE.cs
  56. 2 0
      Emby.Dlna/PlayTo/TransportCommands.cs
  57. 2 0
      Emby.Dlna/PlayTo/UpnpContainer.cs
  58. 2 0
      Emby.Dlna/PlayTo/uBaseObject.cs
  59. 2 0
      Emby.Dlna/PlayTo/uPnpNamespaces.cs
  60. 2 0
      Emby.Dlna/Profiles/DefaultProfile.cs
  61. 2 0
      Emby.Dlna/Profiles/DenonAvrProfile.cs
  62. 2 0
      Emby.Dlna/Profiles/DirectTvProfile.cs
  63. 2 0
      Emby.Dlna/Profiles/DishHopperJoeyProfile.cs
  64. 2 0
      Emby.Dlna/Profiles/Foobar2000Profile.cs
  65. 2 0
      Emby.Dlna/Profiles/LgTvProfile.cs
  66. 2 0
      Emby.Dlna/Profiles/LinksysDMA2100Profile.cs
  67. 2 0
      Emby.Dlna/Profiles/MarantzProfile.cs
  68. 2 0
      Emby.Dlna/Profiles/MediaMonkeyProfile.cs
  69. 2 0
      Emby.Dlna/Profiles/PanasonicVieraProfile.cs
  70. 2 0
      Emby.Dlna/Profiles/PopcornHourProfile.cs
  71. 2 0
      Emby.Dlna/Profiles/SamsungSmartTvProfile.cs
  72. 2 0
      Emby.Dlna/Profiles/SharpSmartTvProfile.cs
  73. 2 0
      Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs
  74. 2 0
      Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs
  75. 2 0
      Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs
  76. 2 0
      Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs
  77. 2 0
      Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs
  78. 2 0
      Emby.Dlna/Profiles/SonyBravia2010Profile.cs
  79. 2 0
      Emby.Dlna/Profiles/SonyBravia2011Profile.cs
  80. 2 0
      Emby.Dlna/Profiles/SonyBravia2012Profile.cs
  81. 2 0
      Emby.Dlna/Profiles/SonyBravia2013Profile.cs
  82. 2 0
      Emby.Dlna/Profiles/SonyBravia2014Profile.cs
  83. 2 0
      Emby.Dlna/Profiles/SonyPs3Profile.cs
  84. 2 0
      Emby.Dlna/Profiles/SonyPs4Profile.cs
  85. 2 0
      Emby.Dlna/Profiles/WdtvLiveProfile.cs
  86. 2 0
      Emby.Dlna/Profiles/XboxOneProfile.cs
  87. 2 1
      Emby.Dlna/Server/DescriptionXmlBuilder.cs
  88. 7 11
      Emby.Dlna/Service/BaseControlHandler.cs
  89. 3 1
      Emby.Dlna/Service/BaseService.cs
  90. 2 0
      Emby.Dlna/Service/ControlErrorHandler.cs
  91. 2 0
      Emby.Dlna/Service/ServiceXmlBuilder.cs
  92. 9 5
      Emby.Dlna/Ssdp/DeviceDiscovery.cs
  93. 2 0
      Emby.Dlna/Ssdp/Extensions.cs
  94. 12 0
      Emby.Drawing/Emby.Drawing.csproj
  95. 34 314
      Emby.Drawing/ImageProcessor.cs
  96. 4 8
      Emby.Naming/Audio/AlbumParser.cs
  97. 3 11
      Emby.Naming/Audio/AudioFileParser.cs
  98. 0 26
      Emby.Naming/Audio/MultiPartResult.cs
  99. 1 1
      Emby.Naming/AudioBook/AudioBookFileInfo.cs
  100. 0 1
      Emby.Naming/AudioBook/AudioBookFilePathParser.cs

+ 1 - 1
.ci/azure-pipelines-main.yml

@@ -43,7 +43,7 @@ jobs:
         displayName: "Build Web Client"
         displayName: "Build Web Client"
         condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
         condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
         inputs:
         inputs:
-          script: yarn install
+          script: yarn install && yarn build
           workingDirectory: $(Agent.TempDirectory)/jellyfin-web
           workingDirectory: $(Agent.TempDirectory)/jellyfin-web
 
 
       - task: CopyFiles@2
       - task: CopyFiles@2

+ 1 - 1
.ci/azure-pipelines-windows.yml

@@ -36,7 +36,7 @@ jobs:
         displayName: "Build Web Client"
         displayName: "Build Web Client"
         condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
         condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion'))
         inputs:
         inputs:
-          script: yarn install
+          script: yarn install && yarn build
           workingDirectory: $(Agent.TempDirectory)/jellyfin-web
           workingDirectory: $(Agent.TempDirectory)/jellyfin-web
 
 
       - task: CopyFiles@2
       - task: CopyFiles@2

+ 13 - 7
.github/ISSUE_TEMPLATE/bug_report.md

@@ -10,6 +10,19 @@ assignees: ''
 **Describe the bug**
 **Describe the bug**
 <!-- A clear and concise description of what the bug is. -->
 <!-- A clear and concise description of what the bug is. -->
 
 
+**System (please complete the following information):**
+ - OS: [e.g. Debian, Windows]
+ - Virtualization: [e.g. Docker, KVM, LXC]
+ - Clients: [Browser, Android, Fire Stick, etc.]
+ - Browser: [e.g. Firefox 72, Chrome 80, Safari 13]
+ - Jellyfin Version: [e.g. 10.4.3, nightly 20191231]
+ - Playback: [Direct Play, Remux, Direct Stream, Transcode] 
+ - Installed Plugins: [e.g. none, Fanart, Anime, etc.]
+ - Reverse Proxy: [e.g. none, nginx, apache, etc.]
+ - Base URL: [e.g. none, yes: /example]
+ - Networking: [e.g. Host, Bridge/NAT]
+ - Storage: [e.g. local, NFS, cloud]
+
 **To Reproduce**
 **To Reproduce**
 <!-- Steps to reproduce the behavior: -->
 <!-- Steps to reproduce the behavior: -->
 1. Go to '...'
 1. Go to '...'
@@ -26,12 +39,5 @@ assignees: ''
 **Screenshots**
 **Screenshots**
 <!-- If applicable, add screenshots to help explain your problem. -->
 <!-- If applicable, add screenshots to help explain your problem. -->
 
 
-**System (please complete the following information):**
- - OS: [e.g. Docker, Debian, Windows]
- - Browser: [e.g. Firefox, Chrome, Safari]
- - Jellyfin Version: [e.g. 10.0.1]
- - Installed Plugins: [e.g. none, Fanart, Anime, etc.]
- - Reverse proxy: [e.g. no, nginx, apache, etc.]
-
 **Additional context**
 **Additional context**
 <!-- Add any other context about the problem here. -->
 <!-- Add any other context about the problem here. -->

+ 120 - 25
CONTRIBUTORS.md

@@ -1,38 +1,133 @@
 # Jellyfin Contributors
 # Jellyfin Contributors
 
 
- - [JoshuaBoniface](https://github.com/joshuaboniface)
- - [nvllsvm](https://github.com/nvllsvm)
- - [JustAMan](https://github.com/JustAMan)
+ - [97carmine](https://github.com/97carmine)
+ - [Abbe98](https://github.com/Abbe98)
+ - [agrenott](https://github.com/agrenott)
+ - [AndreCarvalho](https://github.com/AndreCarvalho)
+ - [anthonylavado](https://github.com/anthonylavado)
+ - [Artiume](https://github.com/Artiume)
+ - [AThomsen](https://github.com/AThomsen)
+ - [bilde2910](https://github.com/bilde2910)
+ - [bfayers](https://github.com/bfayers)
+ - [BnMcG](https://github.com/BnMcG)
+ - [Bond-009](https://github.com/Bond-009)
+ - [brianjmurrell](https://github.com/brianjmurrell)
+ - [bugfixin](https://github.com/bugfixin)
+ - [chaosinnovator](https://github.com/chaosinnovator)
+ - [ckcr4lyf](https://github.com/ckcr4lyf)
+ - [crankdoofus](https://github.com/crankdoofus)
+ - [crobibero](https://github.com/crobibero)
+ - [cromefire](https://github.com/cromefire)
+ - [cryptobank](https://github.com/cryptobank)
+ - [cvium](https://github.com/cvium)
+ - [dannymichel](https://github.com/dannymichel)
+ - [DaveChild](https://github.com/DaveChild)
  - [dcrdev](https://github.com/dcrdev)
  - [dcrdev](https://github.com/dcrdev)
+ - [dhartung](https://github.com/dhartung)
+ - [dinki](https://github.com/dinki)
+ - [dkanada](https://github.com/dkanada)
+ - [dlahoti](https://github.com/dlahoti)
+ - [dmitrylyzo](https://github.com/dmitrylyzo)
+ - [DMouse10462](https://github.com/DMouse10462)
+ - [DrPandemic](https://github.com/DrPandemic)
  - [EraYaN](https://github.com/EraYaN)
  - [EraYaN](https://github.com/EraYaN)
+ - [escabe](https://github.com/escabe)
+ - [excelite](https://github.com/excelite)
+ - [fasheng](https://github.com/fasheng)
+ - [ferferga](https://github.com/ferferga)
+ - [fhriley](https://github.com/fhriley)
  - [flemse](https://github.com/flemse)
  - [flemse](https://github.com/flemse)
- - [bfayers](https://github.com/bfayers)
- - [Bond_009](https://github.com/Bond-009)
- - [AnthonyLavado](https://github.com/anthonylavado)
- - [sparky8251](https://github.com/sparky8251)
- - [LeoVerto](https://github.com/LeoVerto)
+ - [Froghut](https://github.com/Froghut)
+ - [fruhnow](https://github.com/fruhnow)
+ - [geilername](https://github.com/geilername)
+ - [gnattu](https://github.com/gnattu)
  - [grafixeyehero](https://github.com/grafixeyehero)
  - [grafixeyehero](https://github.com/grafixeyehero)
- - [cvium](https://github.com/cvium)
- - [wtayl0r](https://github.com/wtayl0r)
- - [TtheCreator](https://github.com/Tthecreator)
- - [dkanada](https://github.com/dkanada)
- - [LogicalPhallacy](https://github.com/LogicalPhallacy/)
- - [RazeLighter777](https://github.com/RazeLighter777)
- - [WillWill56](https://github.com/WillWill56)
+ - [h1nk](https://github.com/h1nk)
+ - [hawken93](https://github.com/hawken93)
+ - [HelloWorld017](https://github.com/HelloWorld017)
+ - [jftuga](https://github.com/jftuga)
+ - [joern-h](https://github.com/joern-h)
+ - [joshuaboniface](https://github.com/joshuaboniface)
+ - [JustAMan](https://github.com/JustAMan)
+ - [justinfenn](https://github.com/justinfenn)
+ - [KerryRJ](https://github.com/KerryRJ)
+ - [Larvitar](https://github.com/Larvitar)
+ - [LeoVerto](https://github.com/LeoVerto)
  - [Liggy](https://github.com/Liggy)
  - [Liggy](https://github.com/Liggy)
- - [fruhnow](https://github.com/fruhnow)
+ - [LogicalPhallacy](https://github.com/LogicalPhallacy)
+ - [loli10K](https://github.com/loli10K)
+ - [lostmypillow](https://github.com/lostmypillow)
  - [Lynxy](https://github.com/Lynxy)
  - [Lynxy](https://github.com/Lynxy)
- - [fasheng](https://github.com/fasheng)
- - [ploughpuff](https://github.com/ploughpuff)
- - [pjeanjean](https://github.com/pjeanjean)
- - [DrPandemic](https://github.com/drpandemic)
- - [joern-h](https://github.com/joern-h)
- - [Khinenw](https://github.com/HelloWorld017)
- - [fhriley](https://github.com/fhriley)
- - [nevado](https://github.com/nevado)
+ - [ManfredRichthofen](https://github.com/ManfredRichthofen)
+ - [Marenz](https://github.com/Marenz)
+ - [marius-luca-87](https://github.com/marius-luca-87)
  - [mark-monteiro](https://github.com/mark-monteiro)
  - [mark-monteiro](https://github.com/mark-monteiro)
- - [ullmie02](https://github.com/ullmie02)
+ - [Matt07211](https://github.com/Matt07211)
+ - [mcarlton00](https://github.com/mcarlton00)
+ - [mitchfizz05](https://github.com/mitchfizz05)
+ - [MrTimscampi](https://github.com/MrTimscampi)
+ - [n8225](https://github.com/n8225)
+ - [Narfinger](https://github.com/Narfinger)
+ - [NathanPickard](https://github.com/NathanPickard)
+ - [neilsb](https://github.com/neilsb)
+ - [nevado](https://github.com/nevado)
+ - [Nickbert7](https://github.com/Nickbert7)
+ - [nvllsvm](https://github.com/nvllsvm)
+ - [nyanmisaka](https://github.com/nyanmisaka)
+ - [oddstr13](https://github.com/oddstr13)
+ - [petermcneil](https://github.com/petermcneil)
+ - [Phlogi](https://github.com/Phlogi)
+ - [pjeanjean](https://github.com/pjeanjean)
+ - [ploughpuff](https://github.com/ploughpuff)
  - [pR0Ps](https://github.com/pR0Ps)
  - [pR0Ps](https://github.com/pR0Ps)
+ - [PrplHaz4](https://github.com/PrplHaz4)
+ - [RazeLighter777](https://github.com/RazeLighter777)
+ - [redSpoutnik](https://github.com/redSpoutnik)
+ - [ringmatter](https://github.com/ringmatter)
+ - [ryan-hartzell](https://github.com/ryan-hartzell)
+ - [s0urcelab](https://github.com/s0urcelab)
+ - [sachk](https://github.com/sachk)
+ - [sammyrc34](https://github.com/sammyrc34)
+ - [samuel9554](https://github.com/samuel9554)
+ - [scheidleon](https://github.com/scheidleon)
+ - [sebPomme](https://github.com/sebPomme)
+ - [SegiH](https://github.com/SegiH)
+ - [SenorSmartyPants](https://github.com/SenorSmartyPants)
+ - [shemanaev](https://github.com/shemanaev)
+ - [skaro13](https://github.com/skaro13)
+ - [sl1288](https://github.com/sl1288)
+ - [sorinyo2004](https://github.com/sorinyo2004)
+ - [sparky8251](https://github.com/sparky8251)
+ - [stanionascu](https://github.com/stanionascu)
+ - [stevehayles](https://github.com/stevehayles)
+ - [SuperSandro2000](https://github.com/SuperSandro2000)
+ - [tbraeutigam](https://github.com/tbraeutigam)
+ - [teacupx](https://github.com/teacupx)
+ - [Terror-Gene](https://github.com/Terror-Gene)
+ - [ThatNerdyPikachu](https://github.com/ThatNerdyPikachu)
+ - [ThibaultNocchi](https://github.com/ThibaultNocchi)
+ - [thornbill](https://github.com/thornbill)
+ - [ThreeFive-O](https://github.com/ThreeFive-O)
+ - [TrisMcC](https://github.com/TrisMcC)
+ - [trumblejoe](https://github.com/trumblejoe)
+ - [TtheCreator](https://github.com/TtheCreator)
+ - [twinkybot](https://github.com/twinkybot)
+ - [Ullmie02](https://github.com/Ullmie02)
+ - [Unhelpful](https://github.com/Unhelpful)
+ - [viaregio](https://github.com/viaregio)
+ - [vitorsemeano](https://github.com/vitorsemeano)
+ - [voodoos](https://github.com/voodoos)
+ - [whooo](https://github.com/whooo)
+ - [WiiPlayer2](https://github.com/WiiPlayer2)
+ - [WillWill56](https://github.com/WillWill56)
+ - [wtayl0r](https://github.com/wtayl0r)
+ - [Wuerfelbecher](https://github.com/Wuerfelbecher)
+ - [Wunax](https://github.com/Wunax)
+ - [WWWesten](https://github.com/WWWesten)
+ - [WX9yMOXWId](https://github.com/WX9yMOXWId)
+ - [xosdy](https://github.com/xosdy)
+ - [XVicarious](https://github.com/XVicarious)
+ - [YouKnowBlom](https://github.com/YouKnowBlom)
 
 
 # Emby Contributors
 # Emby Contributors
 
 

+ 18 - 4
Dockerfile

@@ -3,7 +3,7 @@ ARG FFMPEG_VERSION=latest
 
 
 FROM node:alpine as web-builder
 FROM node:alpine as web-builder
 ARG JELLYFIN_WEB_VERSION=master
 ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && cd jellyfin-web-* \
  && cd jellyfin-web-* \
  && yarn install \
  && yarn install \
@@ -21,6 +21,13 @@ RUN dotnet publish Jellyfin.Server --disable-parallel --configuration Release --
 FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
 FROM jellyfin/ffmpeg:${FFMPEG_VERSION} as ffmpeg
 FROM debian:buster-slim
 FROM debian:buster-slim
 
 
+# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
+ARG DEBIAN_FRONTEND="noninteractive"
+# http://stackoverflow.com/questions/48162574/ddg#49462622
+ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
+ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
+
 COPY --from=ffmpeg /opt/ffmpeg /opt/ffmpeg
 COPY --from=ffmpeg /opt/ffmpeg /opt/ffmpeg
 COPY --from=builder /jellyfin /jellyfin
 COPY --from=builder /jellyfin /jellyfin
 COPY --from=web-builder /dist /jellyfin/jellyfin-web
 COPY --from=web-builder /dist /jellyfin/jellyfin-web
@@ -31,9 +38,16 @@ COPY --from=web-builder /dist /jellyfin/jellyfin-web
 #   mesa-va-drivers: needed for VAAPI
 #   mesa-va-drivers: needed for VAAPI
 RUN apt-get update \
 RUN apt-get update \
  && apt-get install --no-install-recommends --no-install-suggests -y \
  && apt-get install --no-install-recommends --no-install-suggests -y \
-   libfontconfig1 libgomp1 libva-drm2 mesa-va-drivers openssl \
- && apt-get clean autoclean \
- && apt-get autoremove \
+   libfontconfig1 \
+   libgomp1 \
+   libva-drm2 \
+   mesa-va-drivers \
+   openssl \
+   ca-certificates \
+   vainfo \
+   i965-va-driver \
+ && apt-get clean autoclean -y\
+ && apt-get autoremove -y\
  && rm -rf /var/lib/apt/lists/* \
  && rm -rf /var/lib/apt/lists/* \
  && mkdir -p /cache /config /media \
  && mkdir -p /cache /config /media \
  && chmod 777 /cache /config /media \
  && chmod 777 /cache /config /media \

+ 35 - 4
Dockerfile.arm

@@ -1,9 +1,13 @@
+# DESIGNED FOR BUILDING ON AMD64 ONLY
+#####################################
+# Requires binfm_misc registration
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
 ARG DOTNET_VERSION=3.1
 ARG DOTNET_VERSION=3.1
 
 
 
 
 FROM node:alpine as web-builder
 FROM node:alpine as web-builder
 ARG JELLYFIN_WEB_VERSION=master
 ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && cd jellyfin-web-* \
  && cd jellyfin-web-* \
  && yarn install \
  && yarn install \
@@ -21,10 +25,37 @@ RUN find . -type d -name obj | xargs -r rm -r
 RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
 RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
 
 
 
 
-FROM debian:buster-slim
+FROM multiarch/qemu-user-static:x86_64-arm as qemu
+FROM arm32v7/debian:buster-slim
+
+# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
+ARG DEBIAN_FRONTEND="noninteractive"
+# http://stackoverflow.com/questions/48162574/ddg#49462622
+ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
+ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
+
+COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
 RUN apt-get update \
 RUN apt-get update \
- && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
+ && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg curl && \
+ curl -ks https://repo.jellyfin.org/debian/jellyfin_team.gpg.key | apt-key add - && \
+ curl -s https://keyserver.ubuntu.com/pks/lookup?op=get\&search=0x6587ffd6536b8826e88a62547876ae518cbcf2f2 | apt-key add - && \
+ echo 'deb [arch=armhf] https://repo.jellyfin.org/debian buster main' > /etc/apt/sources.list.d/jellyfin.list && \
+ echo "deb http://ppa.launchpad.net/ubuntu-raspi2/ppa/ubuntu bionic main">> /etc/apt/sources.list.d/raspbins.list && \
+ apt-get update && \
+ apt-get install --no-install-recommends --no-install-suggests -y \
+ jellyfin-ffmpeg \
  libssl-dev \
  libssl-dev \
+ libfontconfig1 \
+ libfreetype6 \
+ libomxil-bellagio0 \
+ libomxil-bellagio-bin \
+ libraspberrypi0 \
+ vainfo \
+ libva2 \
+ && apt-get remove curl gnupg -y \
+ && apt-get clean autoclean -y \
+ && apt-get autoremove -y \
  && rm -rf /var/lib/apt/lists/* \
  && rm -rf /var/lib/apt/lists/* \
  && mkdir -p /cache /config /media \
  && mkdir -p /cache /config /media \
  && chmod 777 /cache /config /media
  && chmod 777 /cache /config /media
@@ -38,4 +69,4 @@ VOLUME /cache /config /media
 ENTRYPOINT ["./jellyfin/jellyfin", \
 ENTRYPOINT ["./jellyfin/jellyfin", \
     "--datadir", "/config", \
     "--datadir", "/config", \
     "--cachedir", "/cache", \
     "--cachedir", "/cache", \
-    "--ffmpeg", "/usr/bin/ffmpeg"]
+    "--ffmpeg", "/usr/lib/jellyfin-ffmpeg"]

+ 24 - 4
Dockerfile.arm64

@@ -1,9 +1,13 @@
+# DESIGNED FOR BUILDING ON AMD64 ONLY
+#####################################
+# Requires binfm_misc registration
+# https://github.com/multiarch/qemu-user-static#binfmt_misc-register
 ARG DOTNET_VERSION=3.1
 ARG DOTNET_VERSION=3.1
 
 
 
 
 FROM node:alpine as web-builder
 FROM node:alpine as web-builder
 ARG JELLYFIN_WEB_VERSION=master
 ARG JELLYFIN_WEB_VERSION=master
-RUN apk add curl \
+RUN apk add curl git \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && curl -L https://github.com/jellyfin/jellyfin-web/archive/${JELLYFIN_WEB_VERSION}.tar.gz | tar zxf - \
  && cd jellyfin-web-* \
  && cd jellyfin-web-* \
  && yarn install \
  && yarn install \
@@ -20,11 +24,27 @@ RUN find . -type d -name obj | xargs -r rm -r
 # Build
 # Build
 RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
 RUN dotnet publish Jellyfin.Server --configuration Release --output="/jellyfin" --self-contained --runtime linux-arm64 "-p:GenerateDocumentationFile=false;DebugSymbols=false;DebugType=none"
 
 
+FROM multiarch/qemu-user-static:x86_64-aarch64 as qemu
+FROM arm64v8/debian:buster-slim
 
 
-FROM debian:buster-slim
-RUN apt-get update \
- && apt-get install --no-install-recommends --no-install-suggests -y ffmpeg \
+# https://askubuntu.com/questions/972516/debian-frontend-environment-variable
+ARG DEBIAN_FRONTEND="noninteractive"
+# http://stackoverflow.com/questions/48162574/ddg#49462622
+ARG APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=DontWarn
+# https://github.com/NVIDIA/nvidia-docker/wiki/Installation-(Native-GPU-Support)
+ENV NVIDIA_DRIVER_CAPABILITIES="compute,video,utility"
+
+COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
+RUN apt-get update && apt-get install --no-install-recommends --no-install-suggests -y \ 
+ ffmpeg \
  libssl-dev \
  libssl-dev \
+ ca-certificates \
+ libfontconfig1 \
+ libfreetype6 \
+ libomxil-bellagio0 \
+ libomxil-bellagio-bin \
+ && apt-get clean autoclean -y \
+ && apt-get autoremove -y \
  && rm -rf /var/lib/apt/lists/* \
  && rm -rf /var/lib/apt/lists/* \
  && mkdir -p /cache /config /media \
  && mkdir -p /cache /config /media \
  && chmod 777 /cache /config /media
  && chmod 777 /cache /config /media

+ 2 - 0
Emby.Dlna/Api/DlnaServerService.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;

+ 2 - 0
Emby.Dlna/Api/DlnaService.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Net;
 using MediaBrowser.Controller.Net;

+ 1 - 0
Emby.Dlna/Common/Argument.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna.Common
 namespace Emby.Dlna.Common
 {
 {

+ 9 - 1
Emby.Dlna/Common/DeviceIcon.cs

@@ -1,3 +1,6 @@
+#pragma warning disable CS1591
+
+using System.Globalization;
 
 
 namespace Emby.Dlna.Common
 namespace Emby.Dlna.Common
 {
 {
@@ -13,9 +16,14 @@ namespace Emby.Dlna.Common
 
 
         public string Depth { get; set; }
         public string Depth { get; set; }
 
 
+        /// <inheritdoc />
         public override string ToString()
         public override string ToString()
         {
         {
-            return string.Format("{0}x{1}", Height, Width);
+            return string.Format(
+                CultureInfo.InvariantCulture,
+                "{0}x{1}",
+                Height,
+                Width);
         }
         }
     }
     }
 }
 }

+ 3 - 3
Emby.Dlna/Common/DeviceService.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna.Common
 namespace Emby.Dlna.Common
 {
 {
@@ -13,9 +14,8 @@ namespace Emby.Dlna.Common
 
 
         public string EventSubUrl { get; set; }
         public string EventSubUrl { get; set; }
 
 
+        /// <inheritdoc />
         public override string ToString()
         public override string ToString()
-        {
-            return string.Format("{0}", ServiceId);
-        }
+            => ServiceId;
     }
     }
 }
 }

+ 8 - 5
Emby.Dlna/Common/ServiceAction.cs

@@ -1,21 +1,24 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace Emby.Dlna.Common
 namespace Emby.Dlna.Common
 {
 {
     public class ServiceAction
     public class ServiceAction
     {
     {
+        public ServiceAction()
+        {
+            ArgumentList = new List<Argument>();
+        }
+
         public string Name { get; set; }
         public string Name { get; set; }
 
 
         public List<Argument> ArgumentList { get; set; }
         public List<Argument> ArgumentList { get; set; }
 
 
+        /// <inheritdoc />
         public override string ToString()
         public override string ToString()
         {
         {
             return Name;
             return Name;
         }
         }
-
-        public ServiceAction()
-        {
-            ArgumentList = new List<Argument>();
-        }
     }
     }
 }
 }

+ 9 - 8
Emby.Dlna/Common/StateVariable.cs

@@ -1,9 +1,16 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.Common
 namespace Emby.Dlna.Common
 {
 {
     public class StateVariable
     public class StateVariable
     {
     {
+        public StateVariable()
+        {
+            AllowedValues = Array.Empty<string>();
+        }
+
         public string Name { get; set; }
         public string Name { get; set; }
 
 
         public string DataType { get; set; }
         public string DataType { get; set; }
@@ -12,14 +19,8 @@ namespace Emby.Dlna.Common
 
 
         public string[] AllowedValues { get; set; }
         public string[] AllowedValues { get; set; }
 
 
+        /// <inheritdoc />
         public override string ToString()
         public override string ToString()
-        {
-            return Name;
-        }
-
-        public StateVariable()
-        {
-            AllowedValues = Array.Empty<string>();
-        }
+            => Name;
     }
     }
 }
 }

+ 17 - 9
Emby.Dlna/Configuration/DlnaOptions.cs

@@ -1,17 +1,9 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna.Configuration
 namespace Emby.Dlna.Configuration
 {
 {
     public class DlnaOptions
     public class DlnaOptions
     {
     {
-        public bool EnablePlayTo { get; set; }
-        public bool EnableServer { get; set; }
-        public bool EnableDebugLog { get; set; }
-        public bool BlastAliveMessages { get; set; }
-        public bool SendOnlyMatchedHost { get; set; }
-        public int ClientDiscoveryIntervalSeconds { get; set; }
-        public int BlastAliveMessageIntervalSeconds { get; set; }
-        public string DefaultUserId { get; set; }
-
         public DlnaOptions()
         public DlnaOptions()
         {
         {
             EnablePlayTo = true;
             EnablePlayTo = true;
@@ -21,5 +13,21 @@ namespace Emby.Dlna.Configuration
             ClientDiscoveryIntervalSeconds = 60;
             ClientDiscoveryIntervalSeconds = 60;
             BlastAliveMessageIntervalSeconds = 1800;
             BlastAliveMessageIntervalSeconds = 1800;
         }
         }
+
+        public bool EnablePlayTo { get; set; }
+
+        public bool EnableServer { get; set; }
+
+        public bool EnableDebugLog { get; set; }
+
+        public bool BlastAliveMessages { get; set; }
+
+        public bool SendOnlyMatchedHost { get; set; }
+
+        public int ClientDiscoveryIntervalSeconds { get; set; }
+
+        public int BlastAliveMessageIntervalSeconds { get; set; }
+
+        public string DefaultUserId { get; set; }
     }
     }
 }
 }

+ 2 - 0
Emby.Dlna/ConfigurationExtension.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Configuration;
 using Emby.Dlna.Configuration;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;

+ 7 - 1
Emby.Dlna/ConnectionManager/ConnectionManager.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
@@ -13,7 +15,11 @@ namespace Emby.Dlna.ConnectionManager
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
 
 
-        public ConnectionManager(IDlnaManager dlna, IServerConfigurationManager config, ILogger logger, IHttpClient httpClient)
+        public ConnectionManager(
+            IDlnaManager dlna,
+            IServerConfigurationManager config,
+            ILogger<ConnectionManager> logger,
+            IHttpClient httpClient)
             : base(logger, httpClient)
             : base(logger, httpClient)
         {
         {
             _dlna = dlna;
             _dlna = dlna;

+ 2 - 0
Emby.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;

+ 16 - 14
Emby.Dlna/ConnectionManager/ControlHandler.cs

@@ -1,5 +1,8 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Xml;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
@@ -12,29 +15,28 @@ namespace Emby.Dlna.ConnectionManager
     {
     {
         private readonly DeviceProfile _profile;
         private readonly DeviceProfile _profile;
 
 
-        protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+        public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
+            : base(config, logger)
+        {
+            _profile = profile;
+        }
+
+        /// <inheritdoc />
+        protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
         {
         {
             if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetProtocolInfo", StringComparison.OrdinalIgnoreCase))
             {
             {
-                return HandleGetProtocolInfo();
+                HandleGetProtocolInfo(xmlWriter);
+                return;
             }
             }
 
 
             throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
             throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetProtocolInfo()
+        private void HandleGetProtocolInfo(XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "Source", _profile.ProtocolInfo },
-                { "Sink", "" }
-            };
-        }
-
-        public ControlHandler(IServerConfigurationManager config, ILogger logger, DeviceProfile profile)
-            : base(config, logger)
-        {
-            _profile = profile;
+            xmlWriter.WriteElementString("Source", _profile.ProtocolInfo);
+            xmlWriter.WriteElementString("Sink", string.Empty);
         }
         }
     }
     }
 }
 }

+ 2 - 0
Emby.Dlna/ConnectionManager/ServiceActionListBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 
 

+ 3 - 1
Emby.Dlna/ContentDirectory/ContentDirectory.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;
@@ -35,7 +37,7 @@ namespace Emby.Dlna.ContentDirectory
             ILibraryManager libraryManager,
             ILibraryManager libraryManager,
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             IUserManager userManager,
             IUserManager userManager,
-            ILogger logger,
+            ILogger<ContentDirectory> logger,
             IHttpClient httpClient,
             IHttpClient httpClient,
             ILocalizationManager localization,
             ILocalizationManager localization,
             IMediaSourceManager mediaSourceManager,
             IMediaSourceManager mediaSourceManager,

+ 2 - 0
Emby.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;

+ 181 - 183
Emby.Dlna/ContentDirectory/ControlHandler.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
@@ -44,7 +46,6 @@ namespace Emby.Dlna.ContentDirectory
         private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
         private const string NS_UPNP = "urn:schemas-upnp-org:metadata-1-0/upnp/";
 
 
         private readonly int _systemUpdateId;
         private readonly int _systemUpdateId;
-        private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 
 
         private readonly DidlBuilder _didlBuilder;
         private readonly DidlBuilder _didlBuilder;
 
 
@@ -58,7 +59,8 @@ namespace Emby.Dlna.ContentDirectory
             string accessToken,
             string accessToken,
             IImageProcessor imageProcessor,
             IImageProcessor imageProcessor,
             IUserDataManager userDataManager,
             IUserDataManager userDataManager,
-            User user, int systemUpdateId,
+            User user,
+            int systemUpdateId,
             IServerConfigurationManager config,
             IServerConfigurationManager config,
             ILocalizationManager localization,
             ILocalizationManager localization,
             IMediaSourceManager mediaSourceManager,
             IMediaSourceManager mediaSourceManager,
@@ -79,114 +81,129 @@ namespace Emby.Dlna.ContentDirectory
             _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
             _didlBuilder = new DidlBuilder(profile, user, imageProcessor, serverAddress, accessToken, userDataManager, localization, mediaSourceManager, Logger, mediaEncoder);
         }
         }
 
 
-        protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+        /// <inheritdoc />
+        protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
         {
         {
-            var deviceId = "test";
-
-            var user = _user;
+            const string DeviceId = "test";
 
 
             if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetSearchCapabilities", StringComparison.OrdinalIgnoreCase))
-                return HandleGetSearchCapabilities();
+            {
+                HandleGetSearchCapabilities(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetSortCapabilities", StringComparison.OrdinalIgnoreCase))
-                return HandleGetSortCapabilities();
+            {
+                HandleGetSortCapabilities(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "GetSortExtensionCapabilities", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetSortExtensionCapabilities", StringComparison.OrdinalIgnoreCase))
-                return HandleGetSortExtensionCapabilities();
+            {
+                HandleGetSortExtensionCapabilities(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetSystemUpdateID", StringComparison.OrdinalIgnoreCase))
-                return HandleGetSystemUpdateID();
+            {
+                HandleGetSystemUpdateID(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "Browse", StringComparison.OrdinalIgnoreCase))
-                return HandleBrowse(methodParams, user, deviceId);
+            {
+                HandleBrowse(xmlWriter, methodParams, DeviceId);
+                return;
+            }
 
 
             if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "X_GetFeatureList", StringComparison.OrdinalIgnoreCase))
-                return HandleXGetFeatureList();
+            {
+                HandleXGetFeatureList(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "GetFeatureList", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "GetFeatureList", StringComparison.OrdinalIgnoreCase))
-                return HandleGetFeatureList();
+            {
+                HandleGetFeatureList(xmlWriter);
+                return;
+            }
 
 
             if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "X_SetBookmark", StringComparison.OrdinalIgnoreCase))
-                return HandleXSetBookmark(methodParams, user);
+            {
+                HandleXSetBookmark(methodParams);
+                return;
+            }
 
 
             if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "Search", StringComparison.OrdinalIgnoreCase))
-                return HandleSearch(methodParams, user, deviceId);
+            {
+                HandleSearch(xmlWriter, methodParams, DeviceId);
+                return;
+            }
 
 
             if (string.Equals(methodName, "X_BrowseByLetter", StringComparison.OrdinalIgnoreCase))
             if (string.Equals(methodName, "X_BrowseByLetter", StringComparison.OrdinalIgnoreCase))
-                return HandleX_BrowseByLetter(methodParams, user, deviceId);
+            {
+                HandleXBrowseByLetter(xmlWriter, methodParams, DeviceId);
+                return;
+            }
 
 
             throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
             throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleXSetBookmark(IDictionary<string, string> sparams, User user)
+        private void HandleXSetBookmark(IDictionary<string, string> sparams)
         {
         {
             var id = sparams["ObjectID"];
             var id = sparams["ObjectID"];
 
 
-            var serverItem = GetItemFromObjectId(id, user);
+            var serverItem = GetItemFromObjectId(id, _user);
 
 
             var item = serverItem.Item;
             var item = serverItem.Item;
 
 
-            var newbookmark = int.Parse(sparams["PosSecond"], _usCulture);
+            var newbookmark = int.Parse(sparams["PosSecond"], CultureInfo.InvariantCulture);
 
 
-            var userdata = _userDataManager.GetUserData(user, item);
+            var userdata = _userDataManager.GetUserData(_user, item);
 
 
             userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
             userdata.PlaybackPositionTicks = TimeSpan.FromSeconds(newbookmark).Ticks;
 
 
-            _userDataManager.SaveUserData(user, item, userdata, UserDataSaveReason.TogglePlayed,
+            _userDataManager.SaveUserData(_user, item, userdata, UserDataSaveReason.TogglePlayed,
                 CancellationToken.None);
                 CancellationToken.None);
-
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetSearchCapabilities()
+        private void HandleGetSearchCapabilities(XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "SearchCaps", "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords" }
-            };
+            xmlWriter.WriteElementString(
+                "SearchCaps",
+                "res@resolution,res@size,res@duration,dc:title,dc:creator,upnp:actor,upnp:artist,upnp:genre,upnp:album,dc:date,upnp:class,@id,@refID,@protocolInfo,upnp:author,dc:description,pv:avKeywords");
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetSortCapabilities()
+        private void HandleGetSortCapabilities(XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "SortCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
-            };
+            xmlWriter.WriteElementString(
+                "SortCaps",
+                "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetSortExtensionCapabilities()
+        private void HandleGetSortExtensionCapabilities(XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "SortExtensionCaps", "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating" }
-            };
+            xmlWriter.WriteElementString(
+                "SortExtensionCaps",
+                "res@duration,res@size,res@bitrate,dc:date,dc:title,dc:size,upnp:album,upnp:artist,upnp:albumArtist,upnp:episodeNumber,upnp:genre,upnp:originalTrackNumber,upnp:rating");
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetSystemUpdateID()
+        private void HandleGetSystemUpdateID(XmlWriter xmlWriter)
         {
         {
-            var headers = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-            headers.Add("Id", _systemUpdateId.ToString(_usCulture));
-            return headers;
+            xmlWriter.WriteElementString("Id", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleGetFeatureList()
+        private void HandleGetFeatureList(XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "FeatureList", GetFeatureListXml() }
-            };
+            xmlWriter.WriteElementString("FeatureList", WriteFeatureListXml());
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleXGetFeatureList()
-        {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
-            {
-                { "FeatureList", GetFeatureListXml() }
-            };
-        }
+        private void HandleXGetFeatureList(XmlWriter xmlWriter)
+            => HandleGetFeatureList(xmlWriter);
 
 
-        private string GetFeatureListXml()
+        private string WriteFeatureListXml()
         {
         {
+            // TODO: clean this up
             var builder = new StringBuilder();
             var builder = new StringBuilder();
 
 
             builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
             builder.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
@@ -213,7 +230,7 @@ namespace Emby.Dlna.ContentDirectory
             return defaultValue;
             return defaultValue;
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleBrowse(IDictionary<string, string> sparams, User user, string deviceId)
+        private void HandleBrowse(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
         {
         {
             var id = sparams["ObjectID"];
             var id = sparams["ObjectID"];
             var flag = sparams["BrowseFlag"];
             var flag = sparams["BrowseFlag"];
@@ -237,101 +254,95 @@ namespace Emby.Dlna.ContentDirectory
                 start = startVal;
                 start = startVal;
             }
             }
 
 
-            var settings = new XmlWriterSettings
-            {
-                Encoding = Encoding.UTF8,
-                CloseOutput = false,
-                OmitXmlDeclaration = true,
-                ConformanceLevel = ConformanceLevel.Fragment
-            };
-
-            StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
-
             int totalCount;
             int totalCount;
 
 
-            var dlnaOptions = _config.GetDlnaConfiguration();
-
-            using (var writer = XmlWriter.Create(builder, settings))
+            using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
             {
             {
-                //writer.WriteStartDocument();
-
-                writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
-
-                writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
-                writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
-                writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
-                //didl.SetAttribute("xmlns:sec", NS_SEC);
-
-                DidlBuilder.WriteXmlRootAttributes(_profile, writer);
-
-                var serverItem = GetItemFromObjectId(id, user);
-                var item = serverItem.Item;
+                var settings = new XmlWriterSettings()
+                {
+                    Encoding = Encoding.UTF8,
+                    CloseOutput = false,
+                    OmitXmlDeclaration = true,
+                    ConformanceLevel = ConformanceLevel.Fragment
+                };
 
 
-                if (string.Equals(flag, "BrowseMetadata"))
+                using (var writer = XmlWriter.Create(builder, settings))
                 {
                 {
-                    totalCount = 1;
+                    writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
 
 
-                    if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
-                    {
-                        var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
+                    writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
+                    writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
+                    writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
 
 
-                        _didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
-                    }
-                    else
-                    {
-                        _didlBuilder.WriteItemElement(dlnaOptions, writer, item, user, null, null, deviceId, filter);
-                    }
+                    DidlBuilder.WriteXmlRootAttributes(_profile, writer);
 
 
-                    provided++;
-                }
-                else
-                {
-                    var childrenResult = GetUserItems(item, serverItem.StubType, user, sortCriteria, start, requestedCount);
-                    totalCount = childrenResult.TotalRecordCount;
+                    var serverItem = GetItemFromObjectId(id, _user);
+                    var item = serverItem.Item;
 
 
-                    provided = childrenResult.Items.Count;
 
 
-                    foreach (var i in childrenResult.Items)
+                    if (string.Equals(flag, "BrowseMetadata", StringComparison.Ordinal))
                     {
                     {
-                        var childItem = i.Item;
-                        var displayStubType = i.StubType;
+                        totalCount = 1;
 
 
-                        if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
+                        if (item.IsDisplayedAsFolder || serverItem.StubType.HasValue)
                         {
                         {
-                            var childCount = (GetUserItems(childItem, displayStubType, user, sortCriteria, null, 0))
-                                .TotalRecordCount;
+                            var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
 
 
-                            _didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
+                            _didlBuilder.WriteFolderElement(writer, item, serverItem.StubType, null, childrenResult.TotalRecordCount, filter, id);
                         }
                         }
                         else
                         else
                         {
                         {
-                            _didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, user, item, serverItem.StubType, deviceId, filter);
+                            var dlnaOptions = _config.GetDlnaConfiguration();
+                            _didlBuilder.WriteItemElement(dlnaOptions, writer, item, _user, null, null, deviceId, filter);
                         }
                         }
+
+                        provided++;
                     }
                     }
+                    else
+                    {
+                        var childrenResult = GetUserItems(item, serverItem.StubType, _user, sortCriteria, start, requestedCount);
+                        totalCount = childrenResult.TotalRecordCount;
+
+                        provided = childrenResult.Items.Count;
+
+                        var dlnaOptions = _config.GetDlnaConfiguration();
+                        foreach (var i in childrenResult.Items)
+                        {
+                            var childItem = i.Item;
+                            var displayStubType = i.StubType;
+
+                            if (childItem.IsDisplayedAsFolder || displayStubType.HasValue)
+                            {
+                                var childCount = GetUserItems(childItem, displayStubType, _user, sortCriteria, null, 0)
+                                    .TotalRecordCount;
+
+                                _didlBuilder.WriteFolderElement(writer, childItem, displayStubType, item, childCount, filter);
+                            }
+                            else
+                            {
+                                _didlBuilder.WriteItemElement(dlnaOptions, writer, childItem, _user, item, serverItem.StubType, deviceId, filter);
+                            }
+                        }
+                    }
+
+                    writer.WriteFullEndElement();
                 }
                 }
 
 
-                writer.WriteFullEndElement();
-                //writer.WriteEndDocument();
+                xmlWriter.WriteElementString("Result", builder.ToString());
             }
             }
 
 
-            var resXML = builder.ToString();
-
-            return new[]
-                {
-                    new KeyValuePair<string,string>("Result", resXML),
-                    new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
-                    new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
-                    new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
-                };
+            xmlWriter.WriteElementString("NumberReturned", provided.ToString(CultureInfo.InvariantCulture));
+            xmlWriter.WriteElementString("TotalMatches", totalCount.ToString(CultureInfo.InvariantCulture));
+            xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleX_BrowseByLetter(IDictionary<string, string> sparams, User user, string deviceId)
+        private void HandleXBrowseByLetter(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
         {
         {
             // TODO: Implement this method
             // TODO: Implement this method
-            return HandleSearch(sparams, user, deviceId);
+            HandleSearch(xmlWriter, sparams, deviceId);
         }
         }
 
 
-        private IEnumerable<KeyValuePair<string, string>> HandleSearch(IDictionary<string, string> sparams, User user, string deviceId)
+        private void HandleSearch(XmlWriter xmlWriter, IDictionary<string, string> sparams, string deviceId)
         {
         {
             var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
             var searchCriteria = new SearchCriteria(GetValueOrDefault(sparams, "SearchCriteria", ""));
             var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
             var sortCriteria = new SortCriteria(GetValueOrDefault(sparams, "SortCriteria", ""));
@@ -354,99 +365,86 @@ namespace Emby.Dlna.ContentDirectory
                 start = startVal;
                 start = startVal;
             }
             }
 
 
-            var settings = new XmlWriterSettings
-            {
-                Encoding = Encoding.UTF8,
-                CloseOutput = false,
-                OmitXmlDeclaration = true,
-                ConformanceLevel = ConformanceLevel.Fragment
-            };
-
-            StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8);
-            int totalCount = 0;
-            int provided = 0;
+            QueryResult<BaseItem> childrenResult;
 
 
-            using (var writer = XmlWriter.Create(builder, settings))
+            using (StringWriter builder = new StringWriterWithEncoding(Encoding.UTF8))
             {
             {
-                //writer.WriteStartDocument();
-
-                writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
-
-                writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
-                writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
-                writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
-                //didl.SetAttribute("xmlns:sec", NS_SEC);
+                var settings = new XmlWriterSettings()
+                {
+                    Encoding = Encoding.UTF8,
+                    CloseOutput = false,
+                    OmitXmlDeclaration = true,
+                    ConformanceLevel = ConformanceLevel.Fragment
+                };
 
 
-                DidlBuilder.WriteXmlRootAttributes(_profile, writer);
+                using (var writer = XmlWriter.Create(builder, settings))
+                {
+                    writer.WriteStartElement(string.Empty, "DIDL-Lite", NS_DIDL);
 
 
-                var serverItem = GetItemFromObjectId(sparams["ContainerID"], user);
+                    writer.WriteAttributeString("xmlns", "dc", null, NS_DC);
+                    writer.WriteAttributeString("xmlns", "dlna", null, NS_DLNA);
+                    writer.WriteAttributeString("xmlns", "upnp", null, NS_UPNP);
 
 
-                var item = serverItem.Item;
+                    DidlBuilder.WriteXmlRootAttributes(_profile, writer);
 
 
-                var childrenResult = (GetChildrenSorted(item, user, searchCriteria, sortCriteria, start, requestedCount));
+                    var serverItem = GetItemFromObjectId(sparams["ContainerID"], _user);
 
 
-                totalCount = childrenResult.TotalRecordCount;
+                    var item = serverItem.Item;
 
 
-                provided = childrenResult.Items.Count;
+                    childrenResult = GetChildrenSorted(item, _user, searchCriteria, sortCriteria, start, requestedCount);
 
 
-                var dlnaOptions = _config.GetDlnaConfiguration();
+                    var dlnaOptions = _config.GetDlnaConfiguration();
 
 
-                foreach (var i in childrenResult.Items)
-                {
-                    if (i.IsDisplayedAsFolder)
+                    foreach (var i in childrenResult.Items)
                     {
                     {
-                        var childCount = (GetChildrenSorted(i, user, searchCriteria, sortCriteria, null, 0))
-                            .TotalRecordCount;
+                        if (i.IsDisplayedAsFolder)
+                        {
+                            var childCount = GetChildrenSorted(i, _user, searchCriteria, sortCriteria, null, 0)
+                                .TotalRecordCount;
 
 
-                        _didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
-                    }
-                    else
-                    {
-                        _didlBuilder.WriteItemElement(dlnaOptions, writer, i, user, item, serverItem.StubType, deviceId, filter);
+                            _didlBuilder.WriteFolderElement(writer, i, null, item, childCount, filter);
+                        }
+                        else
+                        {
+                            _didlBuilder.WriteItemElement(dlnaOptions, writer, i, _user, item, serverItem.StubType, deviceId, filter);
+                        }
                     }
                     }
+
+                    writer.WriteFullEndElement();
                 }
                 }
 
 
-                writer.WriteFullEndElement();
-                //writer.WriteEndDocument();
+                xmlWriter.WriteElementString("Result", builder.ToString());
             }
             }
 
 
-            var resXML = builder.ToString();
-
-            return new List<KeyValuePair<string, string>>
-                {
-                    new KeyValuePair<string,string>("Result", resXML),
-                    new KeyValuePair<string,string>("NumberReturned", provided.ToString(_usCulture)),
-                    new KeyValuePair<string,string>("TotalMatches", totalCount.ToString(_usCulture)),
-                    new KeyValuePair<string,string>("UpdateID", _systemUpdateId.ToString(_usCulture))
-                };
+            xmlWriter.WriteElementString("NumberReturned", childrenResult.Items.Count.ToString(CultureInfo.InvariantCulture));
+            xmlWriter.WriteElementString("TotalMatches", childrenResult.TotalRecordCount.ToString(CultureInfo.InvariantCulture));
+            xmlWriter.WriteElementString("UpdateID", _systemUpdateId.ToString(CultureInfo.InvariantCulture));
         }
         }
 
 
         private QueryResult<BaseItem> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
         private QueryResult<BaseItem> GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
         {
         {
             var folder = (Folder)item;
             var folder = (Folder)item;
 
 
-            var sortOrders = new List<(string, SortOrder)>();
-            if (!folder.IsPreSorted)
-            {
-                sortOrders.Add((ItemSortBy.SortName, sort.SortOrder));
-            }
+            var sortOrders = folder.IsPreSorted
+                ? Array.Empty<(string, SortOrder)>()
+                : new[] { (ItemSortBy.SortName, sort.SortOrder) };
 
 
-            var mediaTypes = new List<string>();
+            string[] mediaTypes = Array.Empty<string>();
             bool? isFolder = null;
             bool? isFolder = null;
 
 
             if (search.SearchType == SearchType.Audio)
             if (search.SearchType == SearchType.Audio)
             {
             {
-                mediaTypes.Add(MediaType.Audio);
+                mediaTypes = new[] { MediaType.Audio };
                 isFolder = false;
                 isFolder = false;
             }
             }
             else if (search.SearchType == SearchType.Video)
             else if (search.SearchType == SearchType.Video)
             {
             {
-                mediaTypes.Add(MediaType.Video);
+                mediaTypes = new[] { MediaType.Video };
                 isFolder = false;
                 isFolder = false;
             }
             }
             else if (search.SearchType == SearchType.Image)
             else if (search.SearchType == SearchType.Image)
             {
             {
-                mediaTypes.Add(MediaType.Photo);
+                mediaTypes = new[] { MediaType.Photo };
                 isFolder = false;
                 isFolder = false;
             }
             }
             else if (search.SearchType == SearchType.Playlist)
             else if (search.SearchType == SearchType.Playlist)
@@ -470,7 +468,7 @@ namespace Emby.Dlna.ContentDirectory
                 IsMissing = false,
                 IsMissing = false,
                 ExcludeItemTypes = new[] { typeof(Book).Name },
                 ExcludeItemTypes = new[] { typeof(Book).Name },
                 IsFolder = isFolder,
                 IsFolder = isFolder,
-                MediaTypes = mediaTypes.ToArray(),
+                MediaTypes = mediaTypes,
                 DtoOptions = GetDtoOptions()
                 DtoOptions = GetDtoOptions()
             });
             });
         }
         }
@@ -1304,11 +1302,11 @@ namespace Emby.Dlna.ContentDirectory
             StubType? stubType = null;
             StubType? stubType = null;
 
 
             // After using PlayTo, MediaMonkey sends a request to the server trying to get item info
             // After using PlayTo, MediaMonkey sends a request to the server trying to get item info
-            const string paramsSrch = "Params=";
-            var paramsIndex = id.IndexOf(paramsSrch, StringComparison.OrdinalIgnoreCase);
+            const string ParamsSrch = "Params=";
+            var paramsIndex = id.IndexOf(ParamsSrch, StringComparison.OrdinalIgnoreCase);
             if (paramsIndex != -1)
             if (paramsIndex != -1)
             {
             {
-                id = id.Substring(paramsIndex + paramsSrch.Length);
+                id = id.Substring(paramsIndex + ParamsSrch.Length);
 
 
                 var parts = id.Split(';');
                 var parts = id.Split(';');
                 id = parts[23];
                 id = parts[23];

+ 2 - 0
Emby.Dlna/ContentDirectory/ServiceActionListBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 
 

+ 2 - 0
Emby.Dlna/ControlRequest.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.IO;
 using System.IO;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http;
 
 

+ 7 - 5
Emby.Dlna/ControlResponse.cs

@@ -1,18 +1,20 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {
     public class ControlResponse
     public class ControlResponse
     {
     {
+        public ControlResponse()
+        {
+            Headers = new Dictionary<string, string>();
+        }
+
         public IDictionary<string, string> Headers { get; set; }
         public IDictionary<string, string> Headers { get; set; }
 
 
         public string Xml { get; set; }
         public string Xml { get; set; }
 
 
         public bool IsSuccessful { get; set; }
         public bool IsSuccessful { get; set; }
-
-        public ControlResponse()
-        {
-            Headers = new Dictionary<string, string>();
-        }
     }
     }
 }
 }

+ 3 - 2
Emby.Dlna/Didl/DidlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
@@ -18,7 +20,6 @@ using MediaBrowser.Controller.Playlists;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Net;
 using MediaBrowser.Model.Net;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
@@ -632,7 +633,7 @@ namespace Emby.Dlna.Didl
             {
             {
                 if (item.PremiereDate.HasValue)
                 if (item.PremiereDate.HasValue)
                 {
                 {
-                    AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o"), NS_DC);
+                    AddValue(writer, "dc", "date", item.PremiereDate.Value.ToString("o", CultureInfo.InvariantCulture), NS_DC);
                 }
                 }
             }
             }
 
 

+ 2 - 0
Emby.Dlna/Didl/Filter.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using MediaBrowser.Model.Extensions;
 using MediaBrowser.Model.Extensions;
 
 

+ 2 - 0
Emby.Dlna/Didl/StringWriterWithEncoding.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;

+ 2 - 0
Emby.Dlna/DlnaManager.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;

+ 13 - 0
Emby.Dlna/Emby.Dlna.csproj

@@ -15,6 +15,19 @@
     <TargetFramework>netstandard2.1</TargetFramework>
     <TargetFramework>netstandard2.1</TargetFramework>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
+    <TreatWarningsAsErrors Condition=" '$(Configuration)' == 'Release'" >true</TreatWarningsAsErrors>
+  </PropertyGroup>
+
+  <!-- Code Analyzers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
   </PropertyGroup>
   </PropertyGroup>
 
 
   <ItemGroup>
   <ItemGroup>

+ 8 - 5
Emby.Dlna/EventSubscriptionResponse.cs

@@ -1,17 +1,20 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {
     public class EventSubscriptionResponse
     public class EventSubscriptionResponse
     {
     {
-        public string Content { get; set; }
-        public string ContentType { get; set; }
-
-        public Dictionary<string, string> Headers { get; set; }
-
         public EventSubscriptionResponse()
         public EventSubscriptionResponse()
         {
         {
             Headers = new Dictionary<string, string>();
             Headers = new Dictionary<string, string>();
         }
         }
+
+        public string Content { get; set; }
+
+        public string ContentType { get; set; }
+
+        public Dictionary<string, string> Headers { get; set; }
     }
     }
 }
 }

+ 4 - 1
Emby.Dlna/Eventing/EventManager.cs

@@ -1,8 +1,11 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
+using System.Net.Http;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
@@ -164,7 +167,7 @@ namespace Emby.Dlna.Eventing
 
 
             try
             try
             {
             {
-                using (await _httpClient.SendAsync(options, "NOTIFY").ConfigureAwait(false))
+                using (await _httpClient.SendAsync(options, new HttpMethod("NOTIFY")).ConfigureAwait(false))
                 {
                 {
 
 
                 }
                 }

+ 4 - 2
Emby.Dlna/Eventing/EventSubscription.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.Eventing
 namespace Emby.Dlna.Eventing
@@ -13,6 +15,8 @@ namespace Emby.Dlna.Eventing
 
 
         public long TriggerCount { get; set; }
         public long TriggerCount { get; set; }
 
 
+        public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
+
         public void IncrementTriggerCount()
         public void IncrementTriggerCount()
         {
         {
             if (TriggerCount == long.MaxValue)
             if (TriggerCount == long.MaxValue)
@@ -22,7 +26,5 @@ namespace Emby.Dlna.Eventing
 
 
             TriggerCount++;
             TriggerCount++;
         }
         }
-
-        public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
     }
     }
 }
 }

+ 1 - 0
Emby.Dlna/IConnectionManager.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {

+ 1 - 0
Emby.Dlna/IContentDirectory.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {

+ 1 - 0
Emby.Dlna/IEventManager.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {

+ 1 - 0
Emby.Dlna/IMediaReceiverRegistrar.cs

@@ -1,3 +1,4 @@
+#pragma warning disable CS1591
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna
 {
 {

+ 2 - 0
Emby.Dlna/IUpnpService.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 
 
 namespace Emby.Dlna
 namespace Emby.Dlna

+ 16 - 5
Emby.Dlna/Main/DlnaEntryPoint.cs

@@ -1,6 +1,8 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
-using System.Net.Sockets;
 using System.Globalization;
 using System.Globalization;
+using System.Net.Sockets;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Dlna.PlayTo;
 using Emby.Dlna.PlayTo;
@@ -24,7 +26,7 @@ using MediaBrowser.Model.System;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
 using Rssdp;
 using Rssdp;
 using Rssdp.Infrastructure;
 using Rssdp.Infrastructure;
-using OperatingSystem =  MediaBrowser.Common.System.OperatingSystem;
+using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
 
 
 namespace Emby.Dlna.Main
 namespace Emby.Dlna.Main
 {
 {
@@ -56,7 +58,9 @@ namespace Emby.Dlna.Main
         private ISsdpCommunicationsServer _communicationsServer;
         private ISsdpCommunicationsServer _communicationsServer;
 
 
         internal IContentDirectory ContentDirectory { get; private set; }
         internal IContentDirectory ContentDirectory { get; private set; }
+
         internal IConnectionManager ConnectionManager { get; private set; }
         internal IConnectionManager ConnectionManager { get; private set; }
+
         internal IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
         internal IMediaReceiverRegistrar MediaReceiverRegistrar { get; private set; }
 
 
         public static DlnaEntryPoint Current;
         public static DlnaEntryPoint Current;
@@ -104,7 +108,7 @@ namespace Emby.Dlna.Main
                 libraryManager,
                 libraryManager,
                 config,
                 config,
                 userManager,
                 userManager,
-                _logger,
+                loggerFactory.CreateLogger<ContentDirectory.ContentDirectory>(),
                 httpClient,
                 httpClient,
                 localizationManager,
                 localizationManager,
                 mediaSourceManager,
                 mediaSourceManager,
@@ -112,9 +116,16 @@ namespace Emby.Dlna.Main
                 mediaEncoder,
                 mediaEncoder,
                 tvSeriesManager);
                 tvSeriesManager);
 
 
-            ConnectionManager = new ConnectionManager.ConnectionManager(dlnaManager, config, _logger, httpClient);
+            ConnectionManager = new ConnectionManager.ConnectionManager(
+                dlnaManager,
+                config,
+                loggerFactory.CreateLogger<ConnectionManager.ConnectionManager>(),
+                httpClient);
 
 
-            MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(_logger, httpClient, config);
+            MediaReceiverRegistrar = new MediaReceiverRegistrar.MediaReceiverRegistrar(
+                loggerFactory.CreateLogger<MediaReceiverRegistrar.MediaReceiverRegistrar>(),
+                httpClient,
+                config);
             Current = this;
             Current = this;
         }
         }
 
 

+ 22 - 21
Emby.Dlna/MediaReceiverRegistrar/ControlHandler.cs

@@ -1,5 +1,8 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
+using System.Xml;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
@@ -9,35 +12,33 @@ namespace Emby.Dlna.MediaReceiverRegistrar
 {
 {
     public class ControlHandler : BaseControlHandler
     public class ControlHandler : BaseControlHandler
     {
     {
-        protected override IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams)
+        public ControlHandler(IServerConfigurationManager config, ILogger logger)
+            : base(config, logger)
         {
         {
-            if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
-                return HandleIsAuthorized();
-            if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
-                return HandleIsValidated();
-
-            throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
         }
         }
 
 
-        private static IEnumerable<KeyValuePair<string, string>> HandleIsAuthorized()
+        /// <inheritdoc />
+        protected override void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter)
         {
         {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+            if (string.Equals(methodName, "IsAuthorized", StringComparison.OrdinalIgnoreCase))
             {
             {
-                { "Result", "1" }
-            };
-        }
+                HandleIsAuthorized(xmlWriter);
+                return;
+            }
 
 
-        private static IEnumerable<KeyValuePair<string, string>> HandleIsValidated()
-        {
-            return new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
+            if (string.Equals(methodName, "IsValidated", StringComparison.OrdinalIgnoreCase))
             {
             {
-                { "Result", "1" }
-            };
-        }
+                HandleIsValidated(xmlWriter);
+                return;
+            }
 
 
-        public ControlHandler(IServerConfigurationManager config, ILogger logger)
-            : base(config, logger)
-        {
+            throw new ResourceNotFoundException("Unexpected control request name: " + methodName);
         }
         }
+
+        private static void HandleIsAuthorized(XmlWriter xmlWriter)
+            => xmlWriter.WriteElementString("Result", "1");
+
+        private static void HandleIsValidated(XmlWriter xmlWriter)
+            => xmlWriter.WriteElementString("Result", "1");
     }
     }
 }
 }

+ 6 - 1
Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrar.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
@@ -10,7 +12,10 @@ namespace Emby.Dlna.MediaReceiverRegistrar
     {
     {
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
 
 
-        public MediaReceiverRegistrar(ILogger logger, IHttpClient httpClient, IServerConfigurationManager config)
+        public MediaReceiverRegistrar(
+            ILogger<MediaReceiverRegistrar> logger,
+            IHttpClient httpClient,
+            IServerConfigurationManager config)
             : base(logger, httpClient)
             : base(logger, httpClient)
         {
         {
             _config = config;
             _config = config;

+ 2 - 0
Emby.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using Emby.Dlna.Service;
 using Emby.Dlna.Service;

+ 2 - 0
Emby.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 
 

+ 17 - 15
Emby.Dlna/PlayTo/Device.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
@@ -221,7 +223,7 @@ namespace Emby.Dlna.PlayTo
             _logger.LogDebug("Setting mute");
             _logger.LogDebug("Setting mute");
             var value = mute ? 1 : 0;
             var value = mute ? 1 : 0;
 
 
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             IsMuted = mute;
             IsMuted = mute;
@@ -251,7 +253,7 @@ namespace Emby.Dlna.PlayTo
             // Remote control will perform better
             // Remote control will perform better
             Volume = value;
             Volume = value;
 
 
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
         }
         }
 
 
@@ -270,7 +272,7 @@ namespace Emby.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
                 throw new InvalidOperationException("Unable to find service");
             }
             }
 
 
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, string.Format("{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"))
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             RestartTimer(true);
             RestartTimer(true);
@@ -302,7 +304,7 @@ namespace Emby.Dlna.PlayTo
             }
             }
 
 
             var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
             var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             await Task.Delay(50).ConfigureAwait(false);
             await Task.Delay(50).ConfigureAwait(false);
@@ -344,7 +346,7 @@ namespace Emby.Dlna.PlayTo
                 throw new InvalidOperationException("Unable to find service");
                 throw new InvalidOperationException("Unable to find service");
             }
             }
 
 
-            return new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
+            return new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1));
         }
         }
 
 
         public async Task SetPlay(CancellationToken cancellationToken)
         public async Task SetPlay(CancellationToken cancellationToken)
@@ -368,7 +370,7 @@ namespace Emby.Dlna.PlayTo
 
 
             var service = GetAvTransportService();
             var service = GetAvTransportService();
 
 
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             RestartTimer(true);
             RestartTimer(true);
@@ -386,7 +388,7 @@ namespace Emby.Dlna.PlayTo
 
 
             var service = GetAvTransportService();
             var service = GetAvTransportService();
 
 
-            await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+            await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             TransportState = TRANSPORTSTATE.PAUSED;
             TransportState = TRANSPORTSTATE.PAUSED;
@@ -513,7 +515,7 @@ namespace Emby.Dlna.PlayTo
                 return;
                 return;
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -559,7 +561,7 @@ namespace Emby.Dlna.PlayTo
                 return;
                 return;
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), true)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -586,7 +588,7 @@ namespace Emby.Dlna.PlayTo
                 return null;
                 return null;
             }
             }
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -624,7 +626,7 @@ namespace Emby.Dlna.PlayTo
 
 
             var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
             var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -687,7 +689,7 @@ namespace Emby.Dlna.PlayTo
 
 
             var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
             var rendererCommands = await GetRenderingProtocolAsync(cancellationToken).ConfigureAwait(false);
 
 
-            var result = await new SsdpHttpClient(_httpClient, _config).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
+            var result = await new SsdpHttpClient(_httpClient).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType), false)
                 .ConfigureAwait(false);
                 .ConfigureAwait(false);
 
 
             if (result == null || result.Document == null)
             if (result == null || result.Document == null)
@@ -868,7 +870,7 @@ namespace Emby.Dlna.PlayTo
 
 
             string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
             string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
 
 
-            var httpClient = new SsdpHttpClient(_httpClient, _config);
+            var httpClient = new SsdpHttpClient(_httpClient);
 
 
             var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
             var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
 
 
@@ -896,7 +898,7 @@ namespace Emby.Dlna.PlayTo
 
 
             string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
             string url = NormalizeUrl(Properties.BaseUrl, avService.ScpdUrl);
 
 
-            var httpClient = new SsdpHttpClient(_httpClient, _config);
+            var httpClient = new SsdpHttpClient(_httpClient);
             _logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
             _logger.LogDebug("Dlna Device.GetRenderingProtocolAsync");
             var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
             var document = await httpClient.GetDataAsync(url, cancellationToken).ConfigureAwait(false);
 
 
@@ -931,7 +933,7 @@ namespace Emby.Dlna.PlayTo
 
 
         public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
         public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClient httpClient, IServerConfigurationManager config, ILogger logger, CancellationToken cancellationToken)
         {
         {
-            var ssdpHttpClient = new SsdpHttpClient(httpClient, config);
+            var ssdpHttpClient = new SsdpHttpClient(httpClient);
 
 
             var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
             var document = await ssdpHttpClient.GetDataAsync(url.ToString(), cancellationToken).ConfigureAwait(false);
 
 

+ 2 - 0
Emby.Dlna/PlayTo/DeviceInfo.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;

+ 2 - 1
Emby.Dlna/PlayTo/PlayToController.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
@@ -6,7 +8,6 @@ using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Emby.Dlna.Didl;
 using Emby.Dlna.Didl;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Common.Configuration;
-using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Dlna;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;

+ 6 - 4
Emby.Dlna/PlayTo/PlayToManager.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.Linq;
 using System.Linq;
@@ -21,7 +23,7 @@ using Microsoft.Extensions.Logging;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo
 {
 {
-    class PlayToManager : IDisposable
+    public class PlayToManager : IDisposable
     {
     {
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly ISessionManager _sessionManager;
         private readonly ISessionManager _sessionManager;
@@ -64,10 +66,10 @@ namespace Emby.Dlna.PlayTo
 
 
         public void Start()
         public void Start()
         {
         {
-            _deviceDiscovery.DeviceDiscovered += _deviceDiscovery_DeviceDiscovered;
+            _deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
         }
         }
 
 
-        async void _deviceDiscovery_DeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
+        private async void OnDeviceDiscoveryDeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e)
         {
         {
             if (_disposed)
             if (_disposed)
             {
             {
@@ -231,7 +233,7 @@ namespace Emby.Dlna.PlayTo
 
 
         public void Dispose()
         public void Dispose()
         {
         {
-            _deviceDiscovery.DeviceDiscovered -= _deviceDiscovery_DeviceDiscovered;
+            _deviceDiscovery.DeviceDiscovered -= OnDeviceDiscoveryDeviceDiscovered;
 
 
             try
             try
             {
             {

+ 2 - 0
Emby.Dlna/PlayTo/PlaybackProgressEventArgs.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 0
Emby.Dlna/PlayTo/PlaybackStartEventArgs.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 0
Emby.Dlna/PlayTo/PlaybackStoppedEventArgs.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 0
Emby.Dlna/PlayTo/PlaylistItem.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 1
Emby.Dlna/PlayTo/PlaylistItemFactory.cs

@@ -1,4 +1,5 @@
-using System.Globalization;
+#pragma warning disable CS1591
+
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;

+ 8 - 6
Emby.Dlna/PlayTo/SsdpHttpClient.cs

@@ -1,13 +1,15 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
+using System.Net.Http;
 using System.Text;
 using System.Text;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Xml.Linq;
 using System.Xml.Linq;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
-using MediaBrowser.Controller.Configuration;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo
 {
 {
@@ -19,12 +21,10 @@ namespace Emby.Dlna.PlayTo
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
         private readonly CultureInfo _usCulture = new CultureInfo("en-US");
 
 
         private readonly IHttpClient _httpClient;
         private readonly IHttpClient _httpClient;
-        private readonly IServerConfigurationManager _config;
 
 
-        public SsdpHttpClient(IHttpClient httpClient, IServerConfigurationManager config)
+        public SsdpHttpClient(IHttpClient httpClient)
         {
         {
             _httpClient = httpClient;
             _httpClient = httpClient;
-            _config = config;
         }
         }
 
 
         public async Task<XDocument> SendCommandAsync(
         public async Task<XDocument> SendCommandAsync(
@@ -64,7 +64,9 @@ namespace Emby.Dlna.PlayTo
             }
             }
 
 
             if (!serviceUrl.StartsWith("/"))
             if (!serviceUrl.StartsWith("/"))
+            {
                 serviceUrl = "/" + serviceUrl;
                 serviceUrl = "/" + serviceUrl;
+            }
 
 
             return baseUrl + serviceUrl;
             return baseUrl + serviceUrl;
         }
         }
@@ -90,7 +92,7 @@ namespace Emby.Dlna.PlayTo
             options.RequestHeaders["NT"] = "upnp:event";
             options.RequestHeaders["NT"] = "upnp:event";
             options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
             options.RequestHeaders["TIMEOUT"] = "Second-" + timeOut.ToString(_usCulture);
 
 
-            using (await _httpClient.SendAsync(options, "SUBSCRIBE").ConfigureAwait(false))
+            using (await _httpClient.SendAsync(options, new HttpMethod("SUBSCRIBE")).ConfigureAwait(false))
             {
             {
 
 
             }
             }
@@ -110,7 +112,7 @@ namespace Emby.Dlna.PlayTo
 
 
             options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
             options.RequestHeaders["FriendlyName.DLNA.ORG"] = FriendlyName;
 
 
-            using (var response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false))
+            using (var response = await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false))
             using (var stream = response.Content)
             using (var stream = response.Content)
             using (var reader = new StreamReader(stream, Encoding.UTF8))
             using (var reader = new StreamReader(stream, Encoding.UTF8))
             {
             {

+ 2 - 0
Emby.Dlna/PlayTo/TRANSPORTSTATE.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo
 {
 {
     public enum TRANSPORTSTATE
     public enum TRANSPORTSTATE

+ 2 - 0
Emby.Dlna/PlayTo/TransportCommands.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;

+ 2 - 0
Emby.Dlna/PlayTo/UpnpContainer.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Xml.Linq;
 using System.Xml.Linq;
 using Emby.Dlna.Ssdp;
 using Emby.Dlna.Ssdp;

+ 2 - 0
Emby.Dlna/PlayTo/uBaseObject.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 0
Emby.Dlna/PlayTo/uPnpNamespaces.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Xml.Linq;
 using System.Xml.Linq;
 
 
 namespace Emby.Dlna.PlayTo
 namespace Emby.Dlna.PlayTo

+ 2 - 0
Emby.Dlna/Profiles/DefaultProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Linq;
 using System.Linq;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 

+ 2 - 0
Emby.Dlna/Profiles/DenonAvrProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/DirectTvProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/DishHopperJoeyProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/Foobar2000Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/LgTvProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/LinksysDMA2100Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/MarantzProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/MediaMonkeyProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/PanasonicVieraProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/PopcornHourProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SamsungSmartTvProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SharpSmartTvProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBlurayPlayer2013.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBlurayPlayer2014.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBlurayPlayer2015.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBlurayPlayer2016.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBlurayPlayerProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBravia2010Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBravia2011Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBravia2012Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBravia2013Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyBravia2014Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyPs3Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/SonyPs4Profile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/WdtvLiveProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 0
Emby.Dlna/Profiles/XboxOneProfile.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
 
 
 namespace Emby.Dlna.Profiles
 namespace Emby.Dlna.Profiles

+ 2 - 1
Emby.Dlna/Server/DescriptionXmlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
@@ -5,7 +7,6 @@ using System.Linq;
 using System.Text;
 using System.Text;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;
 using MediaBrowser.Model.Dlna;
 using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Extensions;
 
 
 namespace Emby.Dlna.Server
 namespace Emby.Dlna.Server
 {
 {

+ 7 - 11
Emby.Dlna/Service/BaseControlHandler.cs

@@ -1,7 +1,8 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.IO;
 using System.IO;
-using System.Linq;
 using System.Text;
 using System.Text;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using System.Xml;
 using System.Xml;
@@ -66,8 +67,6 @@ namespace Emby.Dlna.Service
 
 
             Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
             Logger.LogDebug("Received control request {0}", requestInfo.LocalName);
 
 
-            var result = GetResult(requestInfo.LocalName, requestInfo.Headers);
-
             var settings = new XmlWriterSettings
             var settings = new XmlWriterSettings
             {
             {
                 Encoding = Encoding.UTF8,
                 Encoding = Encoding.UTF8,
@@ -85,12 +84,9 @@ namespace Emby.Dlna.Service
 
 
                 writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
                 writer.WriteStartElement("SOAP-ENV", "Body", NS_SOAPENV);
                 writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
                 writer.WriteStartElement("u", requestInfo.LocalName + "Response", requestInfo.NamespaceURI);
-                foreach (var i in result)
-                {
-                    writer.WriteStartElement(i.Key);
-                    writer.WriteString(i.Value);
-                    writer.WriteFullEndElement();
-                }
+
+                WriteResult(requestInfo.LocalName, requestInfo.Headers, writer);
+
                 writer.WriteFullEndElement();
                 writer.WriteFullEndElement();
                 writer.WriteFullEndElement();
                 writer.WriteFullEndElement();
 
 
@@ -98,7 +94,7 @@ namespace Emby.Dlna.Service
                 writer.WriteEndDocument();
                 writer.WriteEndDocument();
             }
             }
 
 
-            var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=");
+            var xml = builder.ToString().Replace("xmlns:m=", "xmlns:u=", StringComparison.Ordinal);
 
 
             var controlResponse = new ControlResponse
             var controlResponse = new ControlResponse
             {
             {
@@ -219,7 +215,7 @@ namespace Emby.Dlna.Service
             public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
             public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
         }
         }
 
 
-        protected abstract IEnumerable<KeyValuePair<string, string>> GetResult(string methodName, IDictionary<string, string> methodParams);
+        protected abstract void WriteResult(string methodName, IDictionary<string, string> methodParams, XmlWriter xmlWriter);
 
 
         private void LogRequest(ControlRequest request)
         private void LogRequest(ControlRequest request)
         {
         {

+ 3 - 1
Emby.Dlna/Service/BaseService.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using Emby.Dlna.Eventing;
 using Emby.Dlna.Eventing;
 using MediaBrowser.Common.Net;
 using MediaBrowser.Common.Net;
 using Microsoft.Extensions.Logging;
 using Microsoft.Extensions.Logging;
@@ -10,7 +12,7 @@ namespace Emby.Dlna.Service
         protected IHttpClient HttpClient;
         protected IHttpClient HttpClient;
         protected ILogger Logger;
         protected ILogger Logger;
 
 
-        protected BaseService(ILogger logger, IHttpClient httpClient)
+        protected BaseService(ILogger<BaseService> logger, IHttpClient httpClient)
         {
         {
             Logger = logger;
             Logger = logger;
             HttpClient = httpClient;
             HttpClient = httpClient;

+ 2 - 0
Emby.Dlna/Service/ControlErrorHandler.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.IO;
 using System.IO;
 using System.Text;
 using System.Text;

+ 2 - 0
Emby.Dlna/Service/ServiceXmlBuilder.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Text;
 using System.Text;
 using Emby.Dlna.Common;
 using Emby.Dlna.Common;

+ 9 - 5
Emby.Dlna/Ssdp/DeviceDiscovery.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
@@ -9,16 +11,16 @@ using Rssdp.Infrastructure;
 
 
 namespace Emby.Dlna.Ssdp
 namespace Emby.Dlna.Ssdp
 {
 {
-    public class DeviceDiscovery : IDeviceDiscovery
+    public sealed class DeviceDiscovery : IDeviceDiscovery, IDisposable
     {
     {
-        private bool _disposed;
+        private readonly object _syncLock = new object();
 
 
         private readonly IServerConfigurationManager _config;
         private readonly IServerConfigurationManager _config;
 
 
-        private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
-
         private int _listenerCount;
         private int _listenerCount;
-        private object _syncLock = new object();
+        private bool _disposed;
+
+        private event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscoveredInternal;
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered
         public event EventHandler<GenericEventArgs<UpnpDeviceInfo>> DeviceDiscovered
@@ -33,6 +35,7 @@ namespace Emby.Dlna.Ssdp
 
 
                 StartInternal();
                 StartInternal();
             }
             }
+
             remove
             remove
             {
             {
                 lock (_syncLock)
                 lock (_syncLock)
@@ -130,6 +133,7 @@ namespace Emby.Dlna.Ssdp
             DeviceLeft?.Invoke(this, args);
             DeviceLeft?.Invoke(this, args);
         }
         }
 
 
+        /// <inheritdoc />
         public void Dispose()
         public void Dispose()
         {
         {
             if (!_disposed)
             if (!_disposed)

+ 2 - 0
Emby.Dlna/Ssdp/Extensions.cs

@@ -1,3 +1,5 @@
+#pragma warning disable CS1591
+
 using System.Xml.Linq;
 using System.Xml.Linq;
 
 
 namespace Emby.Dlna.Ssdp
 namespace Emby.Dlna.Ssdp

+ 12 - 0
Emby.Drawing/Emby.Drawing.csproj

@@ -17,4 +17,16 @@
     <Compile Include="..\SharedVersion.cs" />
     <Compile Include="..\SharedVersion.cs" />
   </ItemGroup>
   </ItemGroup>
 
 
+  <!-- Code analysers-->
+  <ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.8" PrivateAssets="All" />
+    <PackageReference Include="SerilogAnalyzer" Version="0.15.0" PrivateAssets="All" />
+    <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="All" />
+    <PackageReference Include="SmartAnalyzers.MultithreadingAnalyzer" Version="1.1.31" PrivateAssets="All" />
+  </ItemGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
+    <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+
 </Project>
 </Project>

+ 34 - 314
Emby.Drawing/ImageProcessor.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
-using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller;
 using MediaBrowser.Controller;
@@ -11,7 +10,6 @@ using MediaBrowser.Controller.Drawing;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
 using MediaBrowser.Controller.MediaEncoding;
-using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Drawing;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.IO;
 using MediaBrowser.Model.IO;
@@ -23,7 +21,7 @@ namespace Emby.Drawing
     /// <summary>
     /// <summary>
     /// Class ImageProcessor.
     /// Class ImageProcessor.
     /// </summary>
     /// </summary>
-    public class ImageProcessor : IImageProcessor, IDisposable
+    public sealed class ImageProcessor : IImageProcessor, IDisposable
     {
     {
         // Increment this when there's a change requiring caches to be invalidated
         // Increment this when there's a change requiring caches to be invalidated
         private const string Version = "3";
         private const string Version = "3";
@@ -31,28 +29,24 @@ namespace Emby.Drawing
         private static readonly HashSet<string> _transparentImageTypes
         private static readonly HashSet<string> _transparentImageTypes
             = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
             = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { ".png", ".webp", ".gif" };
 
 
-        /// <summary>
-        /// The _logger
-        /// </summary>
         private readonly ILogger _logger;
         private readonly ILogger _logger;
         private readonly IFileSystem _fileSystem;
         private readonly IFileSystem _fileSystem;
         private readonly IServerApplicationPaths _appPaths;
         private readonly IServerApplicationPaths _appPaths;
-        private IImageEncoder _imageEncoder;
+        private readonly IImageEncoder _imageEncoder;
         private readonly Func<ILibraryManager> _libraryManager;
         private readonly Func<ILibraryManager> _libraryManager;
         private readonly Func<IMediaEncoder> _mediaEncoder;
         private readonly Func<IMediaEncoder> _mediaEncoder;
 
 
-        private readonly Dictionary<string, LockInfo> _locks = new Dictionary<string, LockInfo>();
         private bool _disposed = false;
         private bool _disposed = false;
 
 
         /// <summary>
         /// <summary>
-        ///
+        /// Initializes a new instance of the <see cref="ImageProcessor"/> class.
         /// </summary>
         /// </summary>
-        /// <param name="logger"></param>
-        /// <param name="appPaths"></param>
-        /// <param name="fileSystem"></param>
-        /// <param name="imageEncoder"></param>
-        /// <param name="libraryManager"></param>
-        /// <param name="mediaEncoder"></param>
+        /// <param name="logger">The logger.</param>
+        /// <param name="appPaths">The server application paths.</param>
+        /// <param name="fileSystem">The filesystem.</param>
+        /// <param name="imageEncoder">The image encoder.</param>
+        /// <param name="libraryManager">The library manager.</param>
+        /// <param name="mediaEncoder">The media encoder.</param>
         public ImageProcessor(
         public ImageProcessor(
             ILogger<ImageProcessor> logger,
             ILogger<ImageProcessor> logger,
             IServerApplicationPaths appPaths,
             IServerApplicationPaths appPaths,
@@ -67,16 +61,10 @@ namespace Emby.Drawing
             _libraryManager = libraryManager;
             _libraryManager = libraryManager;
             _mediaEncoder = mediaEncoder;
             _mediaEncoder = mediaEncoder;
             _appPaths = appPaths;
             _appPaths = appPaths;
-
-            ImageEnhancers = Array.Empty<IImageEnhancer>();
-
-            ImageHelper.ImageProcessor = this;
         }
         }
 
 
         private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
         private string ResizedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "resized-images");
 
 
-        private string EnhancedImageCachePath => Path.Combine(_appPaths.ImageCachePath, "enhanced-images");
-
         /// <inheritdoc />
         /// <inheritdoc />
         public IReadOnlyCollection<string> SupportedInputFormats =>
         public IReadOnlyCollection<string> SupportedInputFormats =>
             new HashSet<string>(StringComparer.OrdinalIgnoreCase)
             new HashSet<string>(StringComparer.OrdinalIgnoreCase)
@@ -89,9 +77,7 @@ namespace Emby.Drawing
                 "aiff",
                 "aiff",
                 "cr2",
                 "cr2",
                 "crw",
                 "crw",
-
-                // Remove until supported
-                //"nef",
+                "nef",
                 "orf",
                 "orf",
                 "pef",
                 "pef",
                 "arw",
                 "arw",
@@ -110,19 +96,9 @@ namespace Emby.Drawing
                 "wbmp"
                 "wbmp"
             };
             };
 
 
-        /// <inheritdoc />
-        public IReadOnlyCollection<IImageEnhancer> ImageEnhancers { get; set; }
-
         /// <inheritdoc />
         /// <inheritdoc />
         public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation;
         public bool SupportsImageCollageCreation => _imageEncoder.SupportsImageCollageCreation;
 
 
-        /// <inheritdoc />
-        public IImageEncoder ImageEncoder
-        {
-            get => _imageEncoder;
-            set => _imageEncoder = value ?? throw new ArgumentNullException(nameof(value));
-        }
-
         /// <inheritdoc />
         /// <inheritdoc />
         public async Task ProcessImage(ImageProcessingOptions options, Stream toStream)
         public async Task ProcessImage(ImageProcessingOptions options, Stream toStream)
         {
         {
@@ -150,6 +126,8 @@ namespace Emby.Drawing
                 throw new ArgumentNullException(nameof(options));
                 throw new ArgumentNullException(nameof(options));
             }
             }
 
 
+            var libraryManager = _libraryManager();
+
             ItemImageInfo originalImage = options.Image;
             ItemImageInfo originalImage = options.Image;
             BaseItem item = options.Item;
             BaseItem item = options.Item;
 
 
@@ -157,9 +135,10 @@ namespace Emby.Drawing
             {
             {
                 if (item == null)
                 if (item == null)
                 {
                 {
-                    item = _libraryManager().GetItemById(options.ItemId);
+                    item = libraryManager.GetItemById(options.ItemId);
                 }
                 }
-                originalImage = await _libraryManager().ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
+
+                originalImage = await libraryManager.ConvertImageToLocal(item, originalImage, options.ImageIndex).ConfigureAwait(false);
             }
             }
 
 
             string originalImagePath = originalImage.Path;
             string originalImagePath = originalImage.Path;
@@ -186,27 +165,6 @@ namespace Emby.Drawing
             dateModified = supportedImageInfo.dateModified;
             dateModified = supportedImageInfo.dateModified;
             bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath));
             bool requiresTransparency = _transparentImageTypes.Contains(Path.GetExtension(originalImagePath));
 
 
-            if (options.Enhancers.Count > 0)
-            {
-                if (item == null)
-                {
-                    item = _libraryManager().GetItemById(options.ItemId);
-                }
-
-                var tuple = await GetEnhancedImage(new ItemImageInfo
-                {
-                    DateModified = dateModified,
-                    Type = originalImage.Type,
-                    Path = originalImagePath
-                }, requiresTransparency, item, options.ImageIndex, options.Enhancers, CancellationToken.None).ConfigureAwait(false);
-
-                originalImagePath = tuple.path;
-                dateModified = tuple.dateModified;
-                requiresTransparency = tuple.transparent;
-                // TODO: Get this info
-                originalImageSize = null;
-            }
-
             bool autoOrient = false;
             bool autoOrient = false;
             ImageOrientation? orientation = null;
             ImageOrientation? orientation = null;
             if (item is Photo photo)
             if (item is Photo photo)
@@ -239,12 +197,6 @@ namespace Emby.Drawing
             ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
             ImageFormat outputFormat = GetOutputFormat(options.SupportedOutputFormats, requiresTransparency);
             string cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
             string cacheFilePath = GetCacheFilePath(originalImagePath, newSize, quality, dateModified, outputFormat, options.AddPlayedIndicator, options.PercentPlayed, options.UnplayedCount, options.Blur, options.BackgroundColor, options.ForegroundLayer);
 
 
-            CheckDisposed();
-
-            LockInfo lockInfo = GetLock(cacheFilePath);
-
-            await lockInfo.Lock.WaitAsync().ConfigureAwait(false);
-
             try
             try
             {
             {
                 if (!File.Exists(cacheFilePath))
                 if (!File.Exists(cacheFilePath))
@@ -270,10 +222,6 @@ namespace Emby.Drawing
                 _logger.LogError(ex, "Error encoding image");
                 _logger.LogError(ex, "Error encoding image");
                 return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
                 return (originalImagePath, MimeTypes.GetMimeType(originalImagePath), dateModified);
             }
             }
-            finally
-            {
-                ReleaseLock(cacheFilePath, lockInfo);
-            }
         }
         }
 
 
         private ImageFormat GetOutputFormat(IReadOnlyCollection<ImageFormat> clientSupportedFormats, bool requiresTransparency)
         private ImageFormat GetOutputFormat(IReadOnlyCollection<ImageFormat> clientSupportedFormats, bool requiresTransparency)
@@ -305,20 +253,18 @@ namespace Emby.Drawing
         }
         }
 
 
         private string GetMimeType(ImageFormat format, string path)
         private string GetMimeType(ImageFormat format, string path)
-        {
-            switch(format)
-            {
-                case ImageFormat.Bmp:  return MimeTypes.GetMimeType("i.bmp");
-                case ImageFormat.Gif:  return MimeTypes.GetMimeType("i.gif");
-                case ImageFormat.Jpg:  return MimeTypes.GetMimeType("i.jpg");
-                case ImageFormat.Png:  return MimeTypes.GetMimeType("i.png");
-                case ImageFormat.Webp: return MimeTypes.GetMimeType("i.webp");
-                default:               return MimeTypes.GetMimeType(path);
-            }
-        }
+            => format switch
+            {
+                ImageFormat.Bmp => MimeTypes.GetMimeType("i.bmp"),
+                ImageFormat.Gif => MimeTypes.GetMimeType("i.gif"),
+                ImageFormat.Jpg => MimeTypes.GetMimeType("i.jpg"),
+                ImageFormat.Png => MimeTypes.GetMimeType("i.png"),
+                ImageFormat.Webp => MimeTypes.GetMimeType("i.webp"),
+                _ => MimeTypes.GetMimeType(path)
+            };
 
 
         /// <summary>
         /// <summary>
-        /// Gets the cache file path based on a set of parameters
+        /// Gets the cache file path based on a set of parameters.
         /// </summary>
         /// </summary>
         private string GetCacheFilePath(string originalPath, ImageDimensions outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, string backgroundColor, string foregroundLayer)
         private string GetCacheFilePath(string originalPath, ImageDimensions outputSize, int quality, DateTime dateModified, ImageFormat format, bool addPlayedIndicator, double percentPlayed, int? unwatchedCount, int? blur, string backgroundColor, string foregroundLayer)
         {
         {
@@ -400,11 +346,7 @@ namespace Emby.Drawing
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
         public string GetImageCacheTag(BaseItem item, ItemImageInfo image)
-        {
-            var supportedEnhancers = GetSupportedEnhancers(item, image.Type).ToArray();
-
-            return GetImageCacheTag(item, image, supportedEnhancers);
-        }
+            => (item.Path + image.DateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
 
 
         /// <inheritdoc />
         /// <inheritdoc />
         public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
         public string GetImageCacheTag(BaseItem item, ChapterInfo chapter)
@@ -424,26 +366,6 @@ namespace Emby.Drawing
             }
             }
         }
         }
 
 
-        /// <inheritdoc />
-        public string GetImageCacheTag(BaseItem item, ItemImageInfo image, IReadOnlyCollection<IImageEnhancer> imageEnhancers)
-        {
-            string originalImagePath = image.Path;
-            DateTime dateModified = image.DateModified;
-            ImageType imageType = image.Type;
-
-            // Optimization
-            if (imageEnhancers.Count == 0)
-            {
-                return (originalImagePath + dateModified.Ticks).GetMD5().ToString("N", CultureInfo.InvariantCulture);
-            }
-
-            // Cache name is created with supported enhancers combined with the last config change so we pick up new config changes
-            var cacheKeys = imageEnhancers.Select(i => i.GetConfigurationCacheKey(item, imageType)).ToList();
-            cacheKeys.Add(originalImagePath + dateModified.Ticks);
-
-            return string.Join("|", cacheKeys).GetMD5().ToString("N", CultureInfo.InvariantCulture);
-        }
-
         private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
         private async Task<(string path, DateTime dateModified)> GetSupportedImage(string originalImagePath, DateTime dateModified)
         {
         {
             var inputFormat = Path.GetExtension(originalImagePath)
             var inputFormat = Path.GetExtension(originalImagePath)
@@ -487,154 +409,6 @@ namespace Emby.Drawing
             return (originalImagePath, dateModified);
             return (originalImagePath, dateModified);
         }
         }
 
 
-        /// <inheritdoc />
-        public async Task<string> GetEnhancedImage(BaseItem item, ImageType imageType, int imageIndex)
-        {
-            var enhancers = GetSupportedEnhancers(item, imageType).ToArray();
-
-            ItemImageInfo imageInfo = item.GetImageInfo(imageType, imageIndex);
-
-            bool inputImageSupportsTransparency = SupportsTransparency(imageInfo.Path);
-
-            var result = await GetEnhancedImage(imageInfo, inputImageSupportsTransparency, item, imageIndex, enhancers, CancellationToken.None);
-
-            return result.path;
-        }
-
-        private async Task<(string path, DateTime dateModified, bool transparent)> GetEnhancedImage(
-            ItemImageInfo image,
-            bool inputImageSupportsTransparency,
-            BaseItem item,
-            int imageIndex,
-            IReadOnlyCollection<IImageEnhancer> enhancers,
-            CancellationToken cancellationToken)
-        {
-            var originalImagePath = image.Path;
-            var dateModified = image.DateModified;
-            var imageType = image.Type;
-
-            try
-            {
-                var cacheGuid = GetImageCacheTag(item, image, enhancers);
-
-                // Enhance if we have enhancers
-                var enhancedImageInfo = await GetEnhancedImageInternal(originalImagePath, item, imageType, imageIndex, enhancers, cacheGuid, cancellationToken).ConfigureAwait(false);
-
-                string enhancedImagePath = enhancedImageInfo.path;
-
-                // If the path changed update dateModified
-                if (!string.Equals(enhancedImagePath, originalImagePath, StringComparison.OrdinalIgnoreCase))
-                {
-                    var treatmentRequiresTransparency = enhancedImageInfo.transparent;
-
-                    return (enhancedImagePath, _fileSystem.GetLastWriteTimeUtc(enhancedImagePath), treatmentRequiresTransparency);
-                }
-            }
-            catch (Exception ex)
-            {
-                _logger.LogError(ex, "Error enhancing image");
-            }
-
-            return (originalImagePath, dateModified, inputImageSupportsTransparency);
-        }
-
-        /// <summary>
-        /// Gets the enhanced image internal.
-        /// </summary>
-        /// <param name="originalImagePath">The original image path.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <param name="supportedEnhancers">The supported enhancers.</param>
-        /// <param name="cacheGuid">The cache unique identifier.</param>
-        /// <param name="cancellationToken">The cancellation token.</param>
-        /// <returns>Task&lt;System.String&gt;.</returns>
-        /// <exception cref="ArgumentNullException">
-        /// originalImagePath
-        /// or
-        /// item
-        /// </exception>
-        private async Task<(string path, bool transparent)> GetEnhancedImageInternal(
-            string originalImagePath,
-            BaseItem item,
-            ImageType imageType,
-            int imageIndex,
-            IReadOnlyCollection<IImageEnhancer> supportedEnhancers,
-            string cacheGuid,
-            CancellationToken cancellationToken = default)
-        {
-            if (string.IsNullOrEmpty(originalImagePath))
-            {
-                throw new ArgumentNullException(nameof(originalImagePath));
-            }
-
-            if (item == null)
-            {
-                throw new ArgumentNullException(nameof(item));
-            }
-
-            var treatmentRequiresTransparency = false;
-            foreach (var enhancer in supportedEnhancers)
-            {
-                if (!treatmentRequiresTransparency)
-                {
-                    treatmentRequiresTransparency = enhancer.GetEnhancedImageInfo(item, originalImagePath, imageType, imageIndex).RequiresTransparency;
-                }
-            }
-
-            // All enhanced images are saved as png to allow transparency
-            string cacheExtension = _imageEncoder.SupportedOutputFormats.Contains(ImageFormat.Webp) ?
-                ".webp" :
-                (treatmentRequiresTransparency ? ".png" : ".jpg");
-
-            string enhancedImagePath = GetCachePath(EnhancedImageCachePath, cacheGuid + cacheExtension);
-
-            LockInfo lockInfo = GetLock(enhancedImagePath);
-
-            await lockInfo.Lock.WaitAsync(cancellationToken).ConfigureAwait(false);
-
-            try
-            {
-                // Check again in case of contention
-                if (File.Exists(enhancedImagePath))
-                {
-                    return (enhancedImagePath, treatmentRequiresTransparency);
-                }
-
-                Directory.CreateDirectory(Path.GetDirectoryName(enhancedImagePath));
-
-                await ExecuteImageEnhancers(supportedEnhancers, originalImagePath, enhancedImagePath, item, imageType, imageIndex).ConfigureAwait(false);
-
-                return (enhancedImagePath, treatmentRequiresTransparency);
-            }
-            finally
-            {
-                ReleaseLock(enhancedImagePath, lockInfo);
-            }
-        }
-
-        /// <summary>
-        /// Executes the image enhancers.
-        /// </summary>
-        /// <param name="imageEnhancers">The image enhancers.</param>
-        /// <param name="inputPath">The input path.</param>
-        /// <param name="outputPath">The output path.</param>
-        /// <param name="item">The item.</param>
-        /// <param name="imageType">Type of the image.</param>
-        /// <param name="imageIndex">Index of the image.</param>
-        /// <returns>Task{EnhancedImage}.</returns>
-        private static async Task ExecuteImageEnhancers(IEnumerable<IImageEnhancer> imageEnhancers, string inputPath, string outputPath, BaseItem item, ImageType imageType, int imageIndex)
-        {
-            // Run the enhancers sequentially in order of priority
-            foreach (var enhancer in imageEnhancers)
-            {
-                await enhancer.EnhanceImageAsync(item, inputPath, outputPath, imageType, imageIndex).ConfigureAwait(false);
-
-                // Feed the output into the next enhancer as input
-                inputPath = outputPath;
-            }
-        }
-
         /// <summary>
         /// <summary>
         /// Gets the cache path.
         /// Gets the cache path.
         /// </summary>
         /// </summary>
@@ -647,7 +421,7 @@ namespace Emby.Drawing
         /// or
         /// or
         /// uniqueName
         /// uniqueName
         /// or
         /// or
-        /// fileExtension
+        /// fileExtension.
         /// </exception>
         /// </exception>
         public string GetCachePath(string path, string uniqueName, string fileExtension)
         public string GetCachePath(string path, string uniqueName, string fileExtension)
         {
         {
@@ -680,7 +454,7 @@ namespace Emby.Drawing
         /// <exception cref="ArgumentNullException">
         /// <exception cref="ArgumentNullException">
         /// path
         /// path
         /// or
         /// or
-        /// filename
+        /// filename.
         /// </exception>
         /// </exception>
         public string GetCachePath(string path, string filename)
         public string GetCachePath(string path, string filename)
         {
         {
@@ -688,6 +462,7 @@ namespace Emby.Drawing
             {
             {
                 throw new ArgumentNullException(nameof(path));
                 throw new ArgumentNullException(nameof(path));
             }
             }
+
             if (string.IsNullOrEmpty(filename))
             if (string.IsNullOrEmpty(filename))
             {
             {
                 throw new ArgumentNullException(nameof(filename));
                 throw new ArgumentNullException(nameof(filename));
@@ -709,74 +484,19 @@ namespace Emby.Drawing
         }
         }
 
 
         /// <inheritdoc />
         /// <inheritdoc />
-        public IEnumerable<IImageEnhancer> GetSupportedEnhancers(BaseItem item, ImageType imageType)
-        {
-            foreach (var i in ImageEnhancers)
-            {
-                if (i.Supports(item, imageType))
-                {
-                    yield return i;
-                }
-            }
-        }
-
-
-        private class LockInfo
-        {
-            public SemaphoreSlim Lock = new SemaphoreSlim(1, 1);
-            public int Count = 1;
-        }
-
-        private LockInfo GetLock(string key)
-        {
-            lock (_locks)
-            {
-                if (_locks.TryGetValue(key, out LockInfo info))
-                {
-                    info.Count++;
-                }
-                else
-                {
-                    info = new LockInfo();
-                    _locks[key] = info;
-                }
-                return info;
-            }
-        }
-
-        private void ReleaseLock(string key, LockInfo info)
+        public void Dispose()
         {
         {
-            info.Lock.Release();
-
-            lock (_locks)
+            if (_disposed)
             {
             {
-                info.Count--;
-                if (info.Count <= 0)
-                {
-                    _locks.Remove(key);
-                    info.Lock.Dispose();
-                }
+                return;
             }
             }
-        }
-
-        /// <inheritdoc />
-        public void Dispose()
-        {
-            _disposed = true;
 
 
-            var disposable = _imageEncoder as IDisposable;
-            if (disposable != null)
+            if (_imageEncoder is IDisposable disposable)
             {
             {
                 disposable.Dispose();
                 disposable.Dispose();
             }
             }
-        }
 
 
-        private void CheckDisposed()
-        {
-            if (_disposed)
-            {
-                throw new ObjectDisposedException(GetType().Name);
-            }
+            _disposed = true;
         }
         }
     }
     }
 }
 }

+ 4 - 8
Emby.Naming/Audio/AlbumParser.cs

@@ -1,5 +1,4 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
-#pragma warning disable SA1600
 
 
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;
@@ -19,15 +18,13 @@ namespace Emby.Naming.Audio
             _options = options;
             _options = options;
         }
         }
 
 
-        public MultiPartResult ParseMultiPart(string path)
+        public bool IsMultiPart(string path)
         {
         {
-            var result = new MultiPartResult();
-
             var filename = Path.GetFileName(path);
             var filename = Path.GetFileName(path);
 
 
             if (string.IsNullOrEmpty(filename))
             if (string.IsNullOrEmpty(filename))
             {
             {
-                return result;
+                return false;
             }
             }
 
 
             // TODO: Move this logic into options object
             // TODO: Move this logic into options object
@@ -57,12 +54,11 @@ namespace Emby.Naming.Audio
 
 
                 if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
                 if (int.TryParse(tmp, NumberStyles.Integer, CultureInfo.InvariantCulture, out _))
                 {
                 {
-                    result.IsMultiPart = true;
-                    break;
+                    return true;
                 }
                 }
             }
             }
 
 
-            return result;
+            return false;
         }
         }
     }
     }
 }
 }

+ 3 - 11
Emby.Naming/Audio/AudioFileParser.cs

@@ -1,5 +1,4 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
-#pragma warning disable SA1600
 
 
 using System;
 using System;
 using System.IO;
 using System.IO;
@@ -8,19 +7,12 @@ using Emby.Naming.Common;
 
 
 namespace Emby.Naming.Audio
 namespace Emby.Naming.Audio
 {
 {
-    public class AudioFileParser
+    public static class AudioFileParser
     {
     {
-        private readonly NamingOptions _options;
-
-        public AudioFileParser(NamingOptions options)
-        {
-            _options = options;
-        }
-
-        public bool IsAudioFile(string path)
+        public static bool IsAudioFile(string path, NamingOptions options)
         {
         {
             var extension = Path.GetExtension(path) ?? string.Empty;
             var extension = Path.GetExtension(path) ?? string.Empty;
-            return _options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
+            return options.AudioFileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase);
         }
         }
     }
     }
 }
 }

+ 0 - 26
Emby.Naming/Audio/MultiPartResult.cs

@@ -1,26 +0,0 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
-namespace Emby.Naming.Audio
-{
-    public class MultiPartResult
-    {
-        /// <summary>
-        /// Gets or sets the name.
-        /// </summary>
-        /// <value>The name.</value>
-        public string Name { get; set; }
-
-        /// <summary>
-        /// Gets or sets the part.
-        /// </summary>
-        /// <value>The part.</value>
-        public string Part { get; set; }
-
-        /// <summary>
-        /// Gets or sets a value indicating whether this instance is multi part.
-        /// </summary>
-        /// <value><c>true</c> if this instance is multi part; otherwise, <c>false</c>.</value>
-        public bool IsMultiPart { get; set; }
-    }
-}

+ 1 - 1
Emby.Naming/AudioBook/AudioBookFileInfo.cs

@@ -32,7 +32,7 @@ namespace Emby.Naming.AudioBook
         public int? ChapterNumber { get; set; }
         public int? ChapterNumber { get; set; }
 
 
         /// <summary>
         /// <summary>
-        /// Gets or sets the type.
+        /// Gets or sets a value indicating whether this instance is a directory.
         /// </summary>
         /// </summary>
         /// <value>The type.</value>
         /// <value>The type.</value>
         public bool IsDirectory { get; set; }
         public bool IsDirectory { get; set; }

+ 0 - 1
Emby.Naming/AudioBook/AudioBookFilePathParser.cs

@@ -1,5 +1,4 @@
 #pragma warning disable CS1591
 #pragma warning disable CS1591
-#pragma warning disable SA1600
 
 
 using System;
 using System;
 using System.Globalization;
 using System.Globalization;

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio