Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #40 from Cocotus/DolbyTrueHD_DTSHD/DTSHD-MA_Fix

Dolby true hd dtshd/dtshd ma fix
  • Loading branch information...
commit a3ca5ea6314e96514fa851472cb69dc0485a6942 2 parents fb0658e + c10236f
Chris Motch authored
Showing with 2,078 additions and 89 deletions.
  1. +86 −23 .gitignore
  2. BIN  .nuget/NuGet.exe
  3. +61 −54 Addons/scraper.EmberCore/Scraper/clsScrapeYouTube.vb
  4. +6 −0 Ember Media Manager.sln
  5. +15 −0 Ember Media Manager/App.config
  6. +4 −0 Ember Media Manager/Ember Media Manager.vbproj
  7. +13 −0 Ember Media Manager/dlgEditMovie.vb
  8. +79 −6 Ember Media Manager/frmMain.vb
  9. +86 −0 Ember.Plugins/Dummy/DummyPlugin.cs
  10. +107 −0 Ember.Plugins/Ember.Plugins.csproj
  11. +88 −0 Ember.Plugins/Ember/EmberWorkAroundPlugin.cs
  12. +38 −0 Ember.Plugins/Events/MovieScraper.cs
  13. +70 −0 Ember.Plugins/Events/ShowFormOnUIThread.cs
  14. +45 −0 Ember.Plugins/IPlugin.cs
  15. +9 −0 Ember.Plugins/PluginActionContext.cs
  16. +88 −0 Ember.Plugins/PluginActionResult.cs
  17. +82 −0 Ember.Plugins/PluginBase.cs
  18. +353 −0 Ember.Plugins/PluginManager.cs
  19. +118 −0 Ember.Plugins/PluginSectionHandler.cs
  20. +38 −0 Ember.Plugins/Properties/AssemblyInfo.cs
  21. +35 −0 Ember.Plugins/Properties/Settings.Designer.cs
  22. +9 −0 Ember.Plugins/Properties/Settings.settings
  23. +14 −0 Ember.Plugins/Scraper/Exceptions.cs
  24. +68 −0 Ember.Plugins/Scraper/IMovieImageScraper.cs
  25. +80 −0 Ember.Plugins/Scraper/IMovieInfoScraper.cs
  26. +9 −0 Ember.Plugins/Scraper/ITVImageScraper.cs
  27. +9 −0 Ember.Plugins/Scraper/ITVInfoScraper.cs
  28. +72 −0 Ember.Plugins/Scraper/ImageScrapeActionContext.cs
  29. +211 −0 Ember.Plugins/Scraper/MovieScraperManager.cs
  30. +79 −0 Ember.Plugins/Scraper/ScraperActionContext.cs
  31. +56 −0 Ember.Plugins/Utility.cs
  32. +15 −0 Ember.Plugins/app.config
  33. +16 −0 Ember.Plugins/log4net.config
  34. +4 −0 Ember.Plugins/packages.config
  35. +14 −6 EmberAPI/clsAPIMediaInfo.vb
  36. BIN  packages/SharpZipLib.0.86.0/SharpZipLib.0.86.0.nupkg
  37. BIN  packages/SharpZipLib.0.86.0/lib/11/ICSharpCode.SharpZipLib.dll
  38. BIN  packages/SharpZipLib.0.86.0/lib/20/ICSharpCode.SharpZipLib.dll
  39. BIN  packages/SharpZipLib.0.86.0/lib/SL3/SharpZipLib.Silverlight3.dll
  40. BIN  packages/SharpZipLib.0.86.0/lib/SL4/SharpZipLib.Silverlight4.dll
  41. BIN  packages/System.Data.SQLite.1.0.81.0/System.Data.SQLite.1.0.81.0.nupkg
  42. BIN  packages/System.Data.SQLite.1.0.81.0/lib/net20/System.Data.SQLite.Linq.dll
  43. BIN  packages/System.Data.SQLite.1.0.81.0/lib/net20/System.Data.SQLite.dll
  44. BIN  packages/System.Data.SQLite.1.0.81.0/lib/net40/System.Data.SQLite.Linq.dll
  45. BIN  packages/System.Data.SQLite.1.0.81.0/lib/net40/System.Data.SQLite.dll
  46. +1 −0  packages/repositories.config
109 .gitignore
View
@@ -1,30 +1,93 @@
+# EmberMM build output folders.
+EmberMM-Dev/
+EmberMM-Deploy/
-#ignore thumbnails created by windows
-Thumbs.db
-#Ignore files build by Visual Studio
-*.obj
-*.exe
-*.pdb
+# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
+[Bb]in/
+[Oo]bj/
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
*.user
-*.aps
-*.pch
-*.vspscc
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+x64/
*_i.c
*_p.c
-*.ncb
-*.suo
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
*.tlb
+*.tli
*.tlh
-*.bak
-*.cache
-*.ilk
+*.tmp
*.log
-[Bb]in
-[Dd]ebug*/
-*.lib
-*.sbr
-obj/
-[Rr]elease*/
-_ReSharper*/
-[Tt]est[Rr]esult*
-EmberMM*/
+*.vspscc
+*.vssscc
+.builds
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+packages
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
BIN  .nuget/NuGet.exe
View
Binary file not shown
115 Addons/scraper.EmberCore/Scraper/clsScrapeYouTube.vb
View
@@ -151,61 +151,69 @@ Namespace YouTube
Dim fmtMatch As Match = Regex.Match(Html, "url_encoded_fmt_stream_map=(.*?)\\u0026amp;", RegexOptions.IgnoreCase)
If fmtMatch.Success Then
Dim FormatMap As String = fmtMatch.Groups(1).Value
+ Dim decoded As String = Web.HttpUtility.UrlDecode(FormatMap) & "," ' append comma for easier regex
+
+ Dim pattern As String = "itag=(\d+)&url=(.*?),"
+ Dim rgx As New Regex(pattern, RegexOptions.Singleline)
+ Dim matches As MatchCollection = rgx.Matches(decoded)
+ If matches.Count > 0 Then
+
+ For Each fmt As Match In matches
+ Dim groups As GroupCollection = fmt.Groups
+ Dim Link As New VideoLinkItem
+
+ 'Console.WriteLine("itag: " + groups.Item(1).Value)
+ 'Console.WriteLine("url: " + groups.Item(2).Value)
+ Select Case groups.Item(1).Value
+ Case "18"
+ Link.Description = "SQ (MP4)"
+ Link.FormatQuality = Enums.TrailerQuality.SQMP4
+ Case "22"
+ Link.Description = "720p"
+ Link.FormatQuality = Enums.TrailerQuality.HD720p
+ Case "34"
+ Link.Description = "SQ (FLV)"
+ Link.FormatQuality = Enums.TrailerQuality.SQFLV
+ Case "35"
+ Link.Description = "HQ (FLV)"
+ Link.FormatQuality = Enums.TrailerQuality.HQFLV
+ Case "37"
+ Link.Description = "1080p"
+ Link.FormatQuality = Enums.TrailerQuality.HD1080p
+ Case "46"
+ Link.Description = "1080p (VP8)"
+ Link.FormatQuality = Enums.TrailerQuality.HD1080pVP8
+ Case "45"
+ Link.Description = "720p (VP8)"
+ Link.FormatQuality = Enums.TrailerQuality.HD720pVP8
+ Case "44"
+ Link.Description = "HQ (VP8)"
+ Link.FormatQuality = Enums.TrailerQuality.HQVP8
+ Case "43"
+ Link.Description = "SQ (VP8)"
+ Link.FormatQuality = Enums.TrailerQuality.SQVP8
+ Case Else
+ Link.Description = "Other"
+ Link.FormatQuality = Enums.TrailerQuality.OTHERS
+ 'Continue For
+ End Select
+
+ Link.URL = Web.HttpUtility.UrlDecode(groups.Item(2).Value) & Web.HttpUtility.UrlEncode("&title=" & VideoTitle)
+ Link.URL = Link.URL.Replace("sig=", "signature=") ' sig= returns HTTP 403
+
+ If bwYT.CancellationPending Then Return DownloadLinks
+
+ If Not String.IsNullOrEmpty(Link.URL) AndAlso sHTTP.IsValidURL(Link.URL) Then
+ DownloadLinks.Add(Link)
+ End If
+
+ If bwYT.CancellationPending Then Return DownloadLinks
+
+ Next
- Dim Formats As String() = Web.HttpUtility.UrlDecode(FormatMap).Split(Convert.ToChar(","))
- For Each fmt As String In Formats
- Dim Splitter As String() = {"url=", "&itag="}
- Dim FormatElements As String() = fmt.Split(Splitter, StringSplitOptions.RemoveEmptyEntries)
-
- Dim Link As New VideoLinkItem
-
- Select Case FormatElements(1).Trim
- Case "18"
- Link.Description = "SQ (MP4)"
- Link.FormatQuality = Enums.TrailerQuality.SQMP4
- Case "22"
- Link.Description = "720p"
- Link.FormatQuality = Enums.TrailerQuality.HD720p
- Case "34"
- Link.Description = "SQ (FLV)"
- Link.FormatQuality = Enums.TrailerQuality.SQFLV
- Case "35"
- Link.Description = "HQ (FLV)"
- Link.FormatQuality = Enums.TrailerQuality.HQFLV
- Case "37"
- Link.Description = "1080p"
- Link.FormatQuality = Enums.TrailerQuality.HD1080p
- Case "46"
- Link.Description = "1080p (VP8)"
- Link.FormatQuality = Enums.TrailerQuality.HD1080pVP8
- Case "45"
- Link.Description = "720p (VP8)"
- Link.FormatQuality = Enums.TrailerQuality.HD720pVP8
- Case "44"
- Link.Description = "HQ (VP8)"
- Link.FormatQuality = Enums.TrailerQuality.HQVP8
- Case "43"
- Link.Description = "SQ (VP8)"
- Link.FormatQuality = Enums.TrailerQuality.SQVP8
- Case Else
- Link.Description = "Other"
- Link.FormatQuality = Enums.TrailerQuality.OTHERS
- 'Continue For
- End Select
-
- Link.URL = Web.HttpUtility.UrlDecode(FormatElements(0)) & "&title=" & VideoTitle
-
- If bwYT.CancellationPending Then Return DownloadLinks
-
- If Not String.IsNullOrEmpty(Link.URL) AndAlso sHTTP.IsValidURL(Link.URL) Then
- DownloadLinks.Add(Link)
- End If
-
- If bwYT.CancellationPending Then Return DownloadLinks
-
- Next
- End If
+ End If
+ End If
Return DownloadLinks
Catch ex As Exception
@@ -277,4 +285,3 @@ Namespace YouTube
End Class
End Namespace
-
6 Ember Media Manager.sln
View
@@ -33,6 +33,8 @@ Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "scraper.EmberCore", "Addons
EndProject
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "scraper.EmberCore.XML", "Addons\scraper.EmberCore.XML\scraper.EmberCore.XML.vbproj", "{E567C031-1F7B-4637-9B3A-806988DE50CF}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ember.Plugins", "Ember.Plugins\Ember.Plugins.csproj", "{9496C697-5AFD-4813-AEDC-AF33FACEADF0}"
+EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{8564C91B-7F49-482F-A4B3-C3D7E818648F}"
ProjectSection(SolutionItems) = preProject
.nuget\NuGet.Config = .nuget\NuGet.Config
@@ -106,6 +108,10 @@ Global
{E567C031-1F7B-4637-9B3A-806988DE50CF}.Debug|x86.Build.0 = Debug|x86
{E567C031-1F7B-4637-9B3A-806988DE50CF}.Release|x86.ActiveCfg = Release|x86
{E567C031-1F7B-4637-9B3A-806988DE50CF}.Release|x86.Build.0 = Release|x86
+ {9496C697-5AFD-4813-AEDC-AF33FACEADF0}.Debug|x86.ActiveCfg = Debug|x86
+ {9496C697-5AFD-4813-AEDC-AF33FACEADF0}.Debug|x86.Build.0 = Debug|x86
+ {9496C697-5AFD-4813-AEDC-AF33FACEADF0}.Release|x86.ActiveCfg = Release|x86
+ {9496C697-5AFD-4813-AEDC-AF33FACEADF0}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
15 Ember Media Manager/App.config
View
@@ -1,8 +1,23 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
+ <configSections>
+ <section name="plugins" type="Ember.Plugins.PluginSectionHandler, Ember.Plugins" />
+ </configSections>
+
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true"/>
</settings>
</system.net>
+
+ <runtime>
+ <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+ <probing privatePath="Modules"/>
+ </assemblyBinding>
+ </runtime>
+
+ <plugins>
+ <!-- <plugin class="Ember.Plugins.Dummy.DummyPlugin, Ember.Plugins" /> -->
+ <plugin class="Ember.Plugins.Ember.EmberWorkAroundPlugin, Ember.Plugins" />
+ </plugins>
</configuration>
4 Ember Media Manager/Ember Media Manager.vbproj
View
@@ -473,6 +473,10 @@
<None Include="Resources\EmberSplashScreen.jpg" />
</ItemGroup>
<ItemGroup>
+ <ProjectReference Include="..\Ember.Plugins\Ember.Plugins.csproj">
+ <Project>{9496C697-5AFD-4813-AEDC-AF33FACEADF0}</Project>
+ <Name>Ember.Plugins</Name>
+ </ProjectReference>
<ProjectReference Include="..\EmberAPI\EmberAPI.vbproj">
<Project>{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}</Project>
<Name>EmberAPI</Name>
13 Ember Media Manager/dlgEditMovie.vb
View
@@ -29,6 +29,7 @@ Public Class dlgEditMovie
Friend WithEvents bwThumbs As New System.ComponentModel.BackgroundWorker
+ Private MainForm As frmMain
Private CachePath As String = String.Empty
Private DeleteList As New List(Of String)
Private ExtraIndex As Integer = 0
@@ -46,6 +47,18 @@ Public Class dlgEditMovie
#End Region 'Fields
+#Region "Constructor"
+
+ Public Sub New(MainForm As frmMain)
+ ' This call is required by the designer.
+ InitializeComponent()
+
+ ' Add any initialization after the InitializeComponent() call.
+ Me.MainForm = MainForm
+ End Sub
+
+#End Region 'Constructor
+
#Region "Methods"
Private Sub btnActorDown_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnActorDown.Click
85 Ember Media Manager/frmMain.vb
View
@@ -25,10 +25,13 @@ Imports System.Linq
Imports System.Reflection
Imports System.Text.RegularExpressions
Imports EmberAPI
+Imports Ember.Plugins
+Imports Ember.Plugins.Scraper
Public Class frmMain
#Region "Fields"
+ Private plugin_manager As PluginManager
Private fLoading As New frmSplash
Friend WithEvents bwCleanDB As New System.ComponentModel.BackgroundWorker
@@ -128,6 +131,15 @@ Public Class frmMain
#Region "Properties"
+ Public Property PluginManager As PluginManager
+ Get
+ Return plugin_manager
+ End Get
+ Private Set(value As PluginManager)
+ plugin_manager = value
+ End Set
+ End Property
+
Public Property GenrePanelColor() As Color
Get
Return _genrepanelcolor
@@ -1204,7 +1216,35 @@ Public Class frmMain
dScrapeRow = dRow
Dim DBScrapeMovie As Structures.DBMovie = Master.DB.LoadMovieFromDB(Convert.ToInt64(dRow.Item(0)))
ModulesManager.Instance.RunGeneric(Enums.ModuleEventType.BeforeEditMovie, Nothing, DBScrapeMovie)
- If Not ModulesManager.Instance.MovieScrapeOnly(DBScrapeMovie, Args.scrapeType, Args.Options) Then
+
+
+ '' BEGIN Plug-in Manager
+
+ ' Convert Args.scrapeType into something that the plug-in will understand.
+ Dim ask As Boolean = False
+ Dim scrapeType As Ember.Plugins.Scraper.ScrapeType = scrapeType.Automatic
+ Select Case Args.scrapeType
+ Case Enums.ScrapeType.SingleScrape
+ ask = True
+ scrapeType = Scraper.ScrapeType.Manual
+
+ Case Enums.ScrapeType.FullAsk, _
+ Enums.ScrapeType.NewAsk, _
+ Enums.ScrapeType.UpdateAsk, _
+ Enums.ScrapeType.FilterAsk, _
+ Enums.ScrapeType.MarkAsk
+ ask = True
+ End Select
+
+ Dim context As New MovieInfoScraperActionContext(DBScrapeMovie, scrapeType, ask, Args.Options)
+ Dim result As PluginActionResult = PluginManager.MovieScraper.ScrapeMovieInfo(context)
+ If Not (result.Cancelled Or IsNothing(result.Result)) Then
+ DBScrapeMovie = CType(result.Result, Structures.DBMovie)
+
+ '' END Plug-in Manager
+
+
+ 'If Not ModulesManager.Instance.MovieScrapeOnly(DBScrapeMovie, Args.scrapeType, Args.Options) Then
If Master.eSettings.ScanMediaInfo AndAlso Master.GlobalScrapeMod.Meta Then
MediaInfo.UpdateMediaInfo(DBScrapeMovie)
End If
@@ -1221,7 +1261,12 @@ Public Class frmMain
MovieScraperEvent(Enums.MovieScraperEventType.ListTitle, NewTitle)
MovieScraperEvent(Enums.MovieScraperEventType.SortTitle, DBScrapeMovie.Movie.SortTitle)
- Dim didEts As Interfaces.ModuleResult = ModulesManager.Instance.MoviePostScrapeOnly(DBScrapeMovie, Args.scrapeType)
+ 'Dim didEts As Interfaces.ModuleResult = ModulesManager.Instance.MoviePostScrapeOnly(DBScrapeMovie, Args.scrapeType)
+ Dim imgContext As New MovieImageScraperActionContext(DBScrapeMovie, ImageScrapeType.Poster, scrapeType, context.AskIfMultipleResults)
+ PluginManager.MovieScraper.ScrapeMovieImage(imgContext)
+ imgContext = New MovieImageScraperActionContext(DBScrapeMovie, ImageScrapeType.Fanart, scrapeType, context.AskIfMultipleResults)
+ PluginManager.MovieScraper.ScrapeMovieImage(imgContext)
+
If bwMovieScraper.CancellationPending Then Exit For
@@ -1948,7 +1993,7 @@ doCancel:
Me.SetControlsEnabled(False)
- Using dEditMovie As New dlgEditMovie
+ Using dEditMovie As New dlgEditMovie(Me)
AddHandler ModulesManager.Instance.GenericEvent, AddressOf dEditMovie.GenericRunCallBack
Select Case dEditMovie.ShowDialog()
Case Windows.Forms.DialogResult.OK
@@ -2947,7 +2992,7 @@ doCancel:
Dim ID As Integer = Convert.ToInt32(Me.dgvMediaList.Item(0, indX).Value)
Master.currMovie = Master.DB.LoadMovieFromDB(ID)
- Using dEditMovie As New dlgEditMovie
+ Using dEditMovie As New dlgEditMovie(Me)
AddHandler ModulesManager.Instance.GenericEvent, AddressOf dEditMovie.GenericRunCallBack
Select Case dEditMovie.ShowDialog()
Case Windows.Forms.DialogResult.OK
@@ -3135,7 +3180,7 @@ doCancel:
Master.currMovie = Master.DB.LoadMovieFromDB(ID)
Me.SetStatus(Master.currMovie.Filename)
- Using dEditMovie As New dlgEditMovie
+ Using dEditMovie As New dlgEditMovie(Me)
AddHandler ModulesManager.Instance.GenericEvent, AddressOf dEditMovie.GenericRunCallBack
Select Case dEditMovie.ShowDialog()
Case Windows.Forms.DialogResult.OK
@@ -5269,6 +5314,11 @@ doCancel:
End If
If Not Me.WindowState = FormWindowState.Minimized Then Master.eSettings.Save()
+ If Not IsNothing(PluginManager) Then
+ ' Release any resources held by the plug-in manager or the loaded plug-ins.
+ RemoveHandler PluginManager.ShowFormOnUIThread, AddressOf ShowFormOnUIThread
+ PluginManager.Dispose()
+ End If
Catch ex As Exception
' If we got here, then some of the above not run. Application.Exit can not be used.
' Because Exit will dispose object that are in use by BackgroundWorkers
@@ -5278,6 +5328,25 @@ doCancel:
End Try
End Sub
+ ''' <summary>
+ ''' Shows a form on UI thread.
+ ''' </summary>
+ ''' <param name="sender">The sender.</param>
+ ''' <param name="e">The <see cref="Ember.Plugins.ShowFormOnUIThreadEventArgs" /> instance containing the event data.</param>
+ Private Sub ShowFormOnUIThread(sender As Object, e As Events.ShowFormOnUIThreadEventArgs)
+ If (Me.InvokeRequired) Then
+ Me.Invoke(New Events.ShowFormOnUIThreadHandler(AddressOf ShowFormOnUIThread), _
+ New Object() {sender, e})
+ Return
+ End If
+
+ If e.AsDialog Then
+ e.Form.ShowDialog(Me)
+ Else
+ e.Form.Show(Me)
+ End If
+ End Sub
+
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Try
@@ -5338,6 +5407,10 @@ doCancel:
' Add our handlers, load settings, set form colors, and try to load movies at startup
'\\
fLoading.SetLoadingMesg("Loading modules...")
+ PluginManager = New PluginManager()
+ AddHandler PluginManager.ShowFormOnUIThread, AddressOf ShowFormOnUIThread
+ PluginManager.LoadPlugins()
+
'Setup/Load Modules Manager and set runtime objects (ember application) so they can be exposed to modules
'ExternalModulesManager = New ModulesManager
ModulesManager.Instance.RuntimeObjects.MenuMediaList = Me.mnuMediaList
@@ -6404,7 +6477,7 @@ doCancel:
Me.tslLoading.Text = Master.eLang.GetString(576, "Verifying Movie Details:")
Application.DoEvents()
- Using dEditMovie As New dlgEditMovie
+ Using dEditMovie As New dlgEditMovie(Me)
AddHandler ModulesManager.Instance.GenericEvent, AddressOf dEditMovie.GenericRunCallBack
Select Case dEditMovie.ShowDialog()
Case Windows.Forms.DialogResult.OK
86 Ember.Plugins/Dummy/DummyPlugin.cs
View
@@ -0,0 +1,86 @@
+using Ember.Plugins.Scraper;
+
+namespace Ember.Plugins.Dummy
+{
+ class DummyPlugin
+ : PluginBase
+ {
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ #endregion
+
+
+ #region IPlugin
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the plug-in.
+ /// </summary>
+ public override string Name
+ {
+ get { return "A Dummy Plug-in"; }
+ }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ public override void InitPlugin(PluginManager manager)
+ {
+ base.InitPlugin(manager);
+
+ manager.MovieScraper.PreMovieInfoScrape += PreMovieInfoScraperAction;
+ manager.MovieScraper.PostMovieInfoScrape += PostMovieInfoScraperAction;
+ manager.MovieScraper.PreMovieImageScrape += PreMovieImageScraperAction;
+ manager.MovieScraper.PostMovieImageScrape += PostMovieImageScraperAction;
+ }
+
+ #endregion Methods
+
+ #endregion IPlugin
+
+
+ #region Event Handlers
+
+ private MovieInfoScraperActionContext PreMovieInfoScraperAction(
+ MovieInfoScraperActionContext context)
+ {
+ if (log.IsDebugEnabled)
+ log.Debug("PreMovieInfoScraperAction[Dummy]");
+ return context;
+ }
+
+ private PluginActionResult PostMovieInfoScraperAction(
+ PluginActionResult result)
+ {
+ if (log.IsDebugEnabled)
+ log.Debug("PostMovieInfoScraperAction[Dummy]");
+ return result;
+ }
+
+ private MovieImageScraperActionContext PreMovieImageScraperAction(
+ MovieImageScraperActionContext context)
+ {
+ if (log.IsDebugEnabled)
+ log.Debug("PreMovieImageScraperAction[Dummy]");
+ return context;
+ }
+
+ private PluginActionResult PostMovieImageScraperAction(
+ PluginActionResult result)
+ {
+ if (log.IsDebugEnabled)
+ log.Debug("PostMovieImageScraperAction[Dummy]");
+ return result;
+ }
+
+ #endregion EventHandlers
+
+ }
+}
107 Ember.Plugins/Ember.Plugins.csproj
View
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{9496C697-5AFD-4813-AEDC-AF33FACEADF0}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Ember.Plugins</RootNamespace>
+ <AssemblyName>Ember.Plugins</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>bin\Debug\Ember.Plugins.xml</DocumentationFile>
+ <CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
+ <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <DocumentationFile>bin\Release\Ember.Plugins.xml</DocumentationFile>
+ <PlatformTarget>x86</PlatformTarget>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="log4net">
+ <HintPath>..\packages\log4net.2.0.0\lib\net35-full\log4net.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.configuration" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Windows.Forms" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Dummy\DummyPlugin.cs" />
+ <Compile Include="Ember\EmberWorkAroundPlugin.cs" />
+ <Compile Include="Events\MovieScraper.cs" />
+ <Compile Include="Events\ShowFormOnUIThread.cs" />
+ <Compile Include="IPlugin.cs" />
+ <Compile Include="PluginActionContext.cs" />
+ <Compile Include="PluginActionResult.cs" />
+ <Compile Include="PluginBase.cs" />
+ <Compile Include="PluginManager.cs" />
+ <Compile Include="PluginSectionHandler.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ <DependentUpon>Settings.settings</DependentUpon>
+ </Compile>
+ <Compile Include="Scraper\Exceptions.cs" />
+ <Compile Include="Scraper\ImageScrapeActionContext.cs" />
+ <Compile Include="Scraper\IMovieImageScraper.cs" />
+ <Compile Include="Scraper\IMovieInfoScraper.cs" />
+ <Compile Include="Scraper\ITVImageScraper.cs" />
+ <Compile Include="Scraper\ITVInfoScraper.cs" />
+ <Compile Include="Scraper\MovieScraperManager.cs" />
+ <Compile Include="Scraper\ScraperActionContext.cs" />
+ <Compile Include="Utility.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="app.config" />
+ <None Include="log4net.config">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </None>
+ <None Include="packages.config" />
+ <None Include="Properties\Settings.settings">
+ <Generator>PublicSettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\EmberAPI\EmberAPI.vbproj">
+ <Project>{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}</Project>
+ <Name>EmberAPI</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
88 Ember.Plugins/Ember/EmberWorkAroundPlugin.cs
View
@@ -0,0 +1,88 @@
+using System.Text.RegularExpressions;
+using Ember.Plugins.Scraper;
+
+namespace Ember.Plugins.Ember
+{
+ class EmberWorkAroundPlugin
+ : PluginBase
+ {
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private Regex yearRegex;
+
+ #endregion
+
+
+ #region IPlugin
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the plug-in.
+ /// </summary>
+ public override string Name
+ {
+ get { return "Ember Work Around Plug-in"; }
+ }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ public override void InitPlugin(PluginManager manager)
+ {
+ base.InitPlugin(manager);
+
+ manager.MovieScraper.PreMovieInfoScrape += PreMovieInfoScraperAction;
+ }
+
+ #endregion Methods
+
+ #endregion IPlugin
+
+
+ #region Event Handlers
+
+ /// <summary>
+ /// Fixes the title and year before scraping movie info.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ private MovieInfoScraperActionContext PreMovieInfoScraperAction(
+ MovieInfoScraperActionContext context)
+ {
+ // Check for titles that end with the, a or an that should be at the
+ // start of the title.
+ string title = context.DBMovie.Movie.Title;
+ string lTitle = title.ToLower();
+ if (lTitle.EndsWith(", the"))
+ title = string.Format("The {0}", title.Substring(0, title.LastIndexOf(',')));
+ else if (lTitle.EndsWith(", a"))
+ title = string.Format("A {0}", title.Substring(0, title.LastIndexOf(',')));
+ else if (lTitle.EndsWith(", an"))
+ title = string.Format("An {0}", title.Substring(0, title.LastIndexOf(',')));
+ context.DBMovie.Movie.Title = title;
+
+ // if year is unset try and scrape it from the file name.
+ if (string.IsNullOrEmpty(context.DBMovie.Movie.Year))
+ {
+ if (yearRegex == null)
+ yearRegex = new Regex(@"[\(\[](19|20[0-9]{2})[\]\)]");
+ string filename = context.DBMovie.Filename;
+ Match match = yearRegex.Match(filename);
+ if (match.Success)
+ context.DBMovie.Movie.Year = match.Groups[1].Value;
+ }
+
+ return context;
+ }
+
+ #endregion EventHandlers
+
+ }
+}
38 Ember.Plugins/Events/MovieScraper.cs
View
@@ -0,0 +1,38 @@
+using Ember.Plugins.Scraper;
+
+namespace Ember.Plugins.Events
+{
+
+ /// <summary>
+ /// Delegate for PreMovieInfoScraperAction.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ public delegate MovieInfoScraperActionContext
+ PreMovieInfoScraperActionHandler(MovieInfoScraperActionContext context);
+
+ /// <summary>
+ /// Delegate for PostMovieInfoScraperAction.
+ /// </summary>
+ /// <param name="result">The result.</param>
+ /// <returns></returns>
+ public delegate PluginActionResult
+ PostMovieInfoScraperActionHandler(PluginActionResult result);
+
+ /// <summary>
+ /// Delegate for PreMovieImageScraperAction.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ public delegate MovieImageScraperActionContext
+ PreMovieImageScraperActionHandler(MovieImageScraperActionContext context);
+
+ /// <summary>
+ /// Delegate for PostMovieImageScraperAction.
+ /// </summary>
+ /// <param name="result">The result.</param>
+ /// <returns></returns>
+ public delegate PluginActionResult
+ PostMovieImageScraperActionHandler(PluginActionResult result);
+
+}
70 Ember.Plugins/Events/ShowFormOnUIThread.cs
View
@@ -0,0 +1,70 @@
+using System;
+using System.Windows.Forms;
+
+namespace Ember.Plugins.Events
+{
+
+ /// <summary>
+ /// A delegate to show a form on the UI thread.
+ /// </summary>
+ /// <param name="sender">The plugin making the call.</param>
+ /// <param name="e">The <see cref="ShowFormOnUIThreadEventArgs"/> instance containing the event data.</param>
+ public delegate void ShowFormOnUIThreadHandler(object sender, ShowFormOnUIThreadEventArgs e);
+
+ /// <summary>
+ /// Event arguments for ShowFormOnUIThreadHandler
+ /// </summary>
+ public class ShowFormOnUIThreadEventArgs
+ : EventArgs
+ {
+
+ #region Fields
+
+ private Form form;
+ private bool asDialog;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the form to be shown.
+ /// </summary>
+ public Form Form
+ {
+ get { return form; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether the form should be show as a dialog.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if it should be shown as a dialog; otherwise, <c>false</c>.
+ /// </value>
+ public bool AsDialog
+ {
+ get { return asDialog; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ShowFormOnUIThreadEventArgs"/> class.
+ /// </summary>
+ /// <param name="form">The form to be shown.</param>
+ /// <param name="asDialog">if set to <c>true</c> as dialog.</param>
+ public ShowFormOnUIThreadEventArgs(Form form, bool asDialog)
+ {
+ this.form = form;
+ this.asDialog = asDialog;
+ }
+
+ #endregion Constructor
+
+ }
+
+}
45 Ember.Plugins/IPlugin.cs
View
@@ -0,0 +1,45 @@
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// The Ember Media Manager plug-in interface.
+ /// </summary>
+ public interface IPlugin
+ {
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the plug-in.
+ /// </summary>
+ string Name { get; }
+
+ /// <summary>
+ /// The assembly name of the plug-in.
+ /// </summary>
+ string AssemblyName { get; }
+
+ /// <summary>
+ /// The plug-in version.
+ /// </summary>
+ string Version { get; }
+
+ /// <summary>
+ /// The plug-in manager.
+ /// </summary>
+ PluginManager PluginManager { get; }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ /// <summary>
+ /// Initialises the plugin.
+ /// </summary>
+ /// <param name="manager">The plugin manager.</param>
+ void InitPlugin(PluginManager manager);
+
+ #endregion Methods
+
+ }
+}
9 Ember.Plugins/PluginActionContext.cs
View
@@ -0,0 +1,9 @@
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// Context for a plugin action.
+ /// </summary>
+ public class PluginActionContext
+ {
+ }
+}
88 Ember.Plugins/PluginActionResult.cs
View
@@ -0,0 +1,88 @@
+using System;
+
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// The result of a plug-in action.
+ /// </summary>
+ public class PluginActionResult
+ {
+
+ #region Fields
+
+ private bool cancelled;
+ private bool breakChain;
+ private object result;
+ private Exception error;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets a value indicating whether the action was cancelled.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if cancelled; otherwise, <c>false</c>.
+ /// </value>
+ public bool Cancelled
+ {
+ get { return cancelled; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether this action chain should be broken.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if the action chain should be broken; otherwise, <c>false</c>.
+ /// </value>
+ public bool BreakChain
+ {
+ get { return breakChain; }
+ }
+
+ /// <summary>
+ /// Gets the result of the action.
+ /// </summary>
+ public object Result
+ {
+ get { return result; }
+ }
+
+ /// <summary>
+ /// Gets any exception thrown by the action.
+ /// </summary>
+ public Exception Error
+ {
+ get { return error; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginActionResult"/> class.
+ /// </summary>
+ /// <param name="cancelled">if set to <c>true</c> this action was cancelled.</param>
+ /// <param name="breakChain">if set to <c>true</c> this action chain should be broken.</param>
+ /// <param name="result">The result.</param>
+ /// <param name="error">The error.</param>
+ public PluginActionResult(
+ bool cancelled = false,
+ bool breakChain = false,
+ object result = null,
+ Exception error = null)
+ {
+ this.cancelled = cancelled;
+ this.breakChain = breakChain;
+ this.result = result;
+ this.error = error;
+ }
+
+ #endregion Constructor
+
+ }
+}
82 Ember.Plugins/PluginBase.cs
View
@@ -0,0 +1,82 @@
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// A basic implementation of the plug-in interface.
+ /// </summary>
+ public abstract class PluginBase
+ : IPlugin
+ {
+
+ #region IPlugin
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private PluginManager manager;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// The name of the plug-in.
+ /// </summary>
+ public abstract string Name
+ {
+ get;
+ }
+
+ /// <summary>
+ /// The assembly name of the plug-in.
+ /// </summary>
+ public string AssemblyName
+ {
+ get { return GetType().Assembly.GetName().Name; }
+ }
+
+ /// <summary>
+ /// The plug-in version.
+ /// </summary>
+ public string Version
+ {
+ get { return GetType().Assembly.GetName().Version.ToString(); }
+ }
+
+ /// <summary>
+ /// The plug-in manager.
+ /// </summary>
+ public PluginManager PluginManager
+ {
+ get { return manager; }
+ }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ /// <summary>
+ /// Initialises the plugin.
+ /// </summary>
+ /// <param name="manager">The plugin manager.</param>
+ public virtual void InitPlugin(PluginManager manager)
+ {
+ this.manager = manager;
+
+#if DEBUG
+ if (log.IsDebugEnabled)
+ log.Debug(string.Format(
+ "InitPlugin :: Assembly = {0}; Name = {1}; Version = {2}",
+ AssemblyName, Name, Version));
+#endif
+ }
+
+ #endregion Methods
+
+ #endregion IPlugin
+
+ }
+}
353 Ember.Plugins/PluginManager.cs
View
@@ -0,0 +1,353 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Windows.Forms;
+
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// The plug-in manager for Ember Media Manager.
+ /// </summary>
+ public class PluginManager
+ : IDisposable
+ {
+
+ #region Events
+
+ /// <summary>
+ /// Occurs when a plugin wants to show a form on the UI thread.
+ /// </summary>
+ public event Events.ShowFormOnUIThreadHandler ShowFormOnUIThread;
+
+ #endregion Events
+
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private List<PluginManager.EmberPlugin> plugins = new List<PluginManager.EmberPlugin>();
+ private Scraper.MovieScraperManager movieScraper;
+
+ #endregion
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the loaded plug-ins.
+ /// </summary>
+ public List<PluginManager.EmberPlugin> Plugins
+ {
+ get { return plugins; }
+ }
+
+ /// <summary>
+ /// Gets the Ember.Plugins settings.
+ /// </summary>
+ public Properties.Settings Settings
+ {
+ get { return Properties.Settings.Default; }
+ }
+
+ /// <summary>
+ /// Gets the movie scraper.
+ /// </summary>
+ public Scraper.MovieScraperManager MovieScraper
+ {
+ get { return movieScraper; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginManager"/> class.
+ /// </summary>
+ public PluginManager()
+ {
+ movieScraper = new Scraper.MovieScraperManager(this);
+ }
+
+ #endregion Constructor
+
+
+ #region Methods
+
+ /// <summary>
+ /// Loads and initialise plug-ins listed in the configuration file.
+ /// </summary>
+ public void LoadPlugins()
+ {
+ // Plug-ins loaded by Ember.Plugins.PluginSectionHandler
+ List<IPlugin> loaded = (List<IPlugin>)ConfigurationManager.GetSection("plugins");
+ if (loaded == null || loaded.Count == 0)
+ return;
+
+ foreach (IPlugin plugin in loaded)
+ {
+ bool enabled = true;
+ int order = 0;
+
+ string pluginProp = plugin.AssemblyName.Replace('.', '_');
+ try
+ {
+ string prop = String.Format("Plugin__{0}__Enabled", pluginProp);
+ object value = Settings[prop];
+ enabled = Convert.ToBoolean(value);
+ }
+ catch (SettingsPropertyNotFoundException) { }
+ try
+ {
+ string prop = String.Format("Plugin__{0}__Order", pluginProp);
+ object value = Settings[prop];
+ order = Convert.ToInt32(value);
+ }
+ catch (SettingsPropertyNotFoundException) { }
+
+ PluginManager.EmberPlugin ePlugin = new PluginManager.EmberPlugin(plugin, enabled, order);
+ if (plugins.Contains(ePlugin))
+ {
+#if DEBUG
+ if (log.IsDebugEnabled)
+ log.DebugFormat(
+ "Load Plug-in :: Plugin already loaded. [{0}]",
+ plugin.GetType().Name);
+#endif
+ continue;
+ }
+
+ plugins.Add(ePlugin);
+ ePlugin.Plugin.InitPlugin(this);
+ }
+
+ plugins.Sort();
+ }
+
+ /// <summary>
+ /// Show a form on the UI thread.
+ /// </summary>
+ /// <param name="plugin">The plugin making the call.</param>
+ /// <param name="form">The form to show.</param>
+ /// <param name="asDialog">if set to <c>true</c> as show as a dialog.</param>
+ public void ShowForm(IPlugin plugin, Form form, bool asDialog)
+ {
+ if (ShowFormOnUIThread != null)
+ ShowFormOnUIThread(plugin, new Events.ShowFormOnUIThreadEventArgs(form, asDialog));
+ }
+
+ #endregion
+
+
+ #region IDisposable
+
+ #region Fields
+
+ private bool disposed = false;
+
+ #endregion
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets a value indicating whether the plug-in manager has been disposed of.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance has been disposed of; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsDisposed
+ {
+ get { return disposed; }
+ }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ /// <summary>
+ /// Releases any resources used by the plug-in manager or the loaded plug-ins that implement IDisposable.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ disposed = true;
+
+ // Free other state (managed objects).
+ movieScraper.Dispose();
+
+ foreach (PluginManager.EmberPlugin plugin in plugins)
+ {
+ if (plugin.Plugin is IDisposable)
+ {
+ IDisposable disposable = (IDisposable)plugin.Plugin;
+ disposable.Dispose();
+ }
+ plugins.Remove(plugin);
+
+ foreach (Delegate d in ShowFormOnUIThread.GetInvocationList())
+ ShowFormOnUIThread -= (Events.ShowFormOnUIThreadHandler)d;
+ }
+ }
+
+ // Free your own state (unmanaged objects).
+ // Set large fields to null.
+ }
+
+ /// <summary>
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// <see cref="PluginManager"/> is reclaimed by garbage collection.
+ /// </summary>
+ ~PluginManager()
+ {
+ Dispose(false);
+ }
+
+ #endregion Methods
+
+ #endregion IDisposable
+
+
+ #region Class PluginManager.EmberPlugin
+
+ /// <summary>
+ /// A container for a plug-in.
+ /// </summary>
+ public class EmberPlugin
+ : IComparable<EmberPlugin>, IEquatable<EmberPlugin>
+ {
+
+ #region Fields
+
+ private IPlugin plugin;
+ private bool enabled;
+ private int order;
+
+ #endregion Fields
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the plug-in.
+ /// </summary>
+ public IPlugin Plugin
+ {
+ get { return plugin; }
+ }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether this <see cref="EmberPlugin"/> is enabled.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if enabled; otherwise, <c>false</c>.
+ /// </value>
+ public bool Enabled
+ {
+ get { return enabled; }
+ set { enabled = value; }
+ }
+
+ /// <summary>
+ /// Gets or sets the order this plug-in is called.
+ /// </summary>
+ /// <value>
+ /// The order this plug-in is called..
+ /// </value>
+ public int Order
+ {
+ get { return order; }
+ set { order = value; }
+ }
+
+ #endregion Properties
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="EmberPlugin"/> class.
+ /// </summary>
+ /// <param name="plugin">The plug-in.</param>
+ /// <param name="enabled">if set to <c>true</c> the plug-in is enabled.</param>
+ /// <param name="order">The order this plug-in is called.</param>
+ public EmberPlugin(IPlugin plugin, bool enabled, int order)
+ {
+ if (plugin == null)
+ throw new ArgumentNullException("plugin");
+
+ this.plugin = plugin;
+ this.enabled = enabled;
+ this.order = order;
+ }
+
+ #endregion Constructor
+
+ #region IComparable<EmberPlugin>
+
+ /// <summary>
+ /// Compares the current object with another object of the same type.
+ /// </summary>
+ /// <param name="other">An object to compare with this object.</param>
+ /// <returns>
+ /// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings:
+ /// Value
+ /// Meaning
+ /// Less than zero
+ /// This object is less than the <paramref name="other"/> parameter.
+ /// Zero
+ /// This object is equal to <paramref name="other"/>.
+ /// Greater than zero
+ /// This object is greater than <paramref name="other"/>.
+ /// </returns>
+ public int CompareTo(EmberPlugin other)
+ {
+ if (other == null)
+ return 0;
+
+ return this.Order.CompareTo(other.Order);
+ }
+
+ #endregion IComparable<EmberPlugin>
+
+ #region IEquatable<EmberPlugin>
+
+ /// <summary>
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// </summary>
+ /// <param name="other">An object to compare with this object.</param>
+ /// <returns>
+ /// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
+ /// </returns>
+ public bool Equals(EmberPlugin other)
+ {
+ if (Object.ReferenceEquals(this, other))
+ return true;
+
+ if (Object.ReferenceEquals(other, null))
+ return false;
+
+ return this.Plugin.GetType() == other.Plugin.GetType();
+ }
+
+ #endregion IEquatable<EmberPlugin>
+
+ }
+
+ #endregion Class PluginManager.Plugin
+
+ }
+}
118 Ember.Plugins/PluginSectionHandler.cs
View
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Xml;
+
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// A class to parse plugins section from Application Config
+ /// </summary>
+ public class PluginSectionHandler
+ : IConfigurationSectionHandler
+ {
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ #endregion
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="PluginSectionHandler"/> class.
+ /// </summary>
+ public PluginSectionHandler()
+ {
+ }
+
+ #endregion
+
+
+ #region IConfigurationSectionHandler
+
+ /// <summary>
+ /// Creates a configuration section handler.
+ /// </summary>
+ /// <param name="parent">Parent object.</param>
+ /// <param name="configContext">Configuration context object.</param>
+ /// <param name="section">Section XML node.</param>
+ /// <returns>
+ /// The created section handler object.
+ /// </returns>
+ public object Create(object parent, object configContext, XmlNode section)
+ {
+ List<IPlugin> plugins = new List<IPlugin>();
+
+ if (!Properties.Settings.Default.AllowPlugins)
+ {
+#if DEBUG
+ if (log.IsDebugEnabled) log.Debug("Load Plug-in :: Plug-ins disabled.");
+#endif
+ return plugins;
+ }
+
+ foreach (XmlNode node in section.ChildNodes)
+ {
+ string className = null;
+ try
+ {
+ if (node.Attributes["class"] == null)
+ throw new PluginSectionHandler.InvalidConfigException();
+ className = node.Attributes["class"].Value;
+ if (string.IsNullOrEmpty(className)) continue;
+
+#if DEBUG
+ if (log.IsDebugEnabled)
+ log.Debug(string.Format("Load Plug-in :: ClassName = {0}", className));
+#endif
+
+ Type pluginType = Type.GetType(className);
+ if (pluginType == null)
+ throw new PluginSectionHandler.UnknownClassException();
+ object pluginObject = Activator.CreateInstance(pluginType);
+ if (pluginObject == null || !(pluginObject is IPlugin)) continue;
+
+ IPlugin plugin = (IPlugin)pluginObject;
+ plugins.Add(plugin);
+ }
+ catch (PluginSectionHandler.InvalidConfigException)
+ {
+ if (log.IsErrorEnabled)
+ log.Error("Load Plug-in :: Plug-in configuration error. No class type found for plug-in.");
+ }
+ catch (PluginSectionHandler.UnknownClassException)
+ {
+ if (log.IsErrorEnabled)
+ {
+ string[] classSplit = className.Split(',');
+ log.ErrorFormat(
+ "Load Plug-in :: Plug-in configuration error. Unable to load plugin class. [Assembly={1}; Class={0}]",
+ classSplit[0].TrimStart(), classSplit[1]);
+ log.Error("Load Plug-in :: Check the plug-in entry and that it's located in the Modules directory.");
+ }
+ }
+ catch (Exception ex)
+ {
+ if (log.IsErrorEnabled)
+ log.Error("Load Plug-in :: Plug-in configuration error.", ex);
+ }
+ }
+
+ return plugins;
+ }
+
+ #endregion
+
+
+ #region PluginSectionHandler Exceptions
+
+ private class InvalidConfigException : Exception { }
+ private class UnknownClassException : Exception { }
+
+ #endregion PluginSectionHandler Exceptions
+ }
+}
38 Ember.Plugins/Properties/AssemblyInfo.cs
View
@@ -0,0 +1,38 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Ember.Plugins")]
+[assembly: AssemblyDescription("A plug-in framework for Ember Media Manager.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Ember Media Manager")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("d57d89fc-6578-497e-886a-ee7a057543e9")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+
+[assembly: log4net.Config.XmlConfigurator(ConfigFile = "log4net.config", Watch = true)]
35 Ember.Plugins/Properties/Settings.Designer.cs
View
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.269
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Ember.Plugins.Properties {
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
+ public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default {
+ get {
+ return defaultInstance;
+ }
+ }
+
+ [global::System.Configuration.ApplicationScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("True")]
+ public bool AllowPlugins {
+ get {
+ return ((bool)(this["AllowPlugins"]));
+ }
+ }
+ }
+}
9 Ember.Plugins/Properties/Settings.settings
View
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Ember.Plugins.Properties" GeneratedClassName="Settings">
+ <Profiles />
+ <Settings>
+ <Setting Name="AllowPlugins" Type="System.Boolean" Scope="Application">
+ <Value Profile="(Default)">True</Value>
+ </Setting>
+ </Settings>
+</SettingsFile>
14 Ember.Plugins/Scraper/Exceptions.cs
View
@@ -0,0 +1,14 @@
+using System;
+
+namespace Ember.Plugins.Scraper
+{
+
+ /// <summary>
+ /// Exception thrown when a scrape has been cancelled.
+ /// </summary>
+ public class CancelScrapeException
+ : Exception
+ {
+ }
+
+}
68 Ember.Plugins/Scraper/IMovieImageScraper.cs
View
@@ -0,0 +1,68 @@
+using EmberAPI;
+
+namespace Ember.Plugins.Scraper
+{
+ /// <summary>
+ /// Defines a movie image scraper.
+ /// </summary>
+ public interface IMovieImageScraper
+ {
+
+ /// <summary>
+ /// Scrapes the movie posters.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ PluginActionResult ScrapeMovieImage(MovieImageScraperActionContext context);
+
+ }
+
+ /// <summary>
+ /// Context for a movie image scraper action.
+ /// </summary>
+ public class MovieImageScraperActionContext
+ : ImageScrapeActionContext
+ {
+
+ #region Fields
+
+ private Structures.DBMovie dbMovie;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the movie.
+ /// </summary>
+ public Structures.DBMovie DBMovie
+ {
+ get { return dbMovie; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MovieImageScraperActionContext"/> class.
+ /// </summary>
+ /// <param name="dbMovie">The movie.</param>
+ /// <param name="scrapeType">The type of scrape to perform.</param>
+ /// <param name="askIfMultipleResults">if set to <c>true</c> ask the user to select a movie if multiple results are found.</param>
+ public MovieImageScraperActionContext(
+ Structures.DBMovie dbMovie,
+ ImageScrapeType imageScrapeType,
+ ScrapeType scrapeType,
+ bool askIfMultipleResults)
+ : base(imageScrapeType, scrapeType, askIfMultipleResults)
+ {
+ this.dbMovie = dbMovie;
+ }
+
+ #endregion Constructor
+
+ }
+}
80 Ember.Plugins/Scraper/IMovieInfoScraper.cs
View
@@ -0,0 +1,80 @@
+using EmberAPI;
+
+namespace Ember.Plugins.Scraper
+{
+
+ /// <summary>
+ /// Defines a movie information scraper.
+ /// </summary>
+ public interface IMovieInfoScraper
+ {
+
+ /// <summary>
+ /// Scrapes the movie info.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ PluginActionResult ScrapeMovieInfo(MovieInfoScraperActionContext context);
+
+ }
+
+ /// <summary>
+ /// Context for a movie information scraper action.
+ /// </summary>
+ public class MovieInfoScraperActionContext
+ : ScraperActionContext
+ {
+
+ #region Fields
+
+ private Structures.DBMovie dbMovie;
+ private Structures.ScrapeOptions options;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the movie.
+ /// </summary>
+ public Structures.DBMovie DBMovie
+ {
+ get { return dbMovie; }
+ }
+
+ /// <summary>
+ /// Gets the global scraper options.
+ /// </summary>
+ public Structures.ScrapeOptions Options
+ {
+ get { return options; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MovieInfoScraperActionContext"/> class.
+ /// </summary>
+ /// <param name="dbMovie">The movie.</param>
+ /// <param name="scrapeType">The type of scrape to perform.</param>
+ /// <param name="askIfMultipleResults">if set to <c>true</c> ask the user to select a movie if multiple results are found.</param>
+ /// <param name="options">The global scraper options.</param>
+ public MovieInfoScraperActionContext(
+ Structures.DBMovie dbMovie,
+ ScrapeType scrapeType,
+ bool askIfMultipleResults,
+ Structures.ScrapeOptions options)
+ : base(scrapeType, askIfMultipleResults)
+ {
+ this.dbMovie = dbMovie;
+ this.options = options;
+ }
+
+ #endregion Constructor
+
+ }
+}
9 Ember.Plugins/Scraper/ITVImageScraper.cs
View
@@ -0,0 +1,9 @@
+namespace Ember.Plugins.Scraper
+{
+ /// <summary>
+ /// Defines a TV show image scraper.
+ /// </summary>
+ public interface ITVImageScraper
+ {
+ }
+}
9 Ember.Plugins/Scraper/ITVInfoScraper.cs
View
@@ -0,0 +1,9 @@
+namespace Ember.Plugins.Scraper
+{
+ /// <summary>
+ /// Defines a TV show information scraper.
+ /// </summary>
+ public interface ITVInfoScraper
+ {
+ }
+}
72 Ember.Plugins/Scraper/ImageScrapeActionContext.cs
View
@@ -0,0 +1,72 @@
+namespace Ember.Plugins.Scraper
+{
+
+ /// <summary>
+ /// The type of image scrape to perform.
+ /// </summary>
+ public enum ImageScrapeType
+ {
+ /// <summary>
+ /// Scrape a poster.
+ /// </summary>
+ Poster,
+
+ /// <summary>
+ /// Scrape fanart.
+ /// </summary>
+ Fanart,
+ }
+
+
+ /// <summary>
+ /// Context for image scraper actions.
+ /// </summary>
+ public class ImageScrapeActionContext
+ : ScraperActionContext
+ {
+
+ #region Fields
+
+ private ImageScrapeType imageScrapeType;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the type of image scrape to perform.
+ /// </summary>
+ /// <value>
+ /// The type of image scrape to perform.
+ /// </value>
+ public ImageScrapeType ImageScrapeType
+ {
+ get { return imageScrapeType; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ImageScrapeActionContext"/> class.
+ /// </summary>
+ /// <param name="imageScrapeType">Type of the image scrape.</param>
+ /// <param name="scrapeType">Type of the scrape.</param>
+ /// <param name="askIfMultipleResults">if set to <c>true</c> [ask if multiple results].</param>
+ public ImageScrapeActionContext(
+ ImageScrapeType imageScrapeType,
+ ScrapeType scrapeType,
+ bool askIfMultipleResults)
+ : base(scrapeType, askIfMultipleResults)
+ {
+ this.imageScrapeType = imageScrapeType;
+ }
+
+ #endregion Constructor
+
+ }
+
+}
211 Ember.Plugins/Scraper/MovieScraperManager.cs
View
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Ember.Plugins.Scraper
+{
+ /// <summary>
+ /// The main interface for calling movie scraper plug-ins.
+ /// </summary>
+ public class MovieScraperManager
+ : IDisposable, IMovieInfoScraper, IMovieImageScraper
+ {
+
+ #region Events
+
+ /// <summary>
+ /// Occurs before movie information is scraped.
+ /// </summary>
+ public event Events.PreMovieInfoScraperActionHandler PreMovieInfoScrape;
+
+ /// <summary>
+ /// Occurs after movie information is scraped.
+ /// </summary>
+ public event Events.PostMovieInfoScraperActionHandler PostMovieInfoScrape;
+
+ /// <summary>
+ /// Occurs before movie poster is scraped.
+ /// </summary>
+ public event Events.PreMovieImageScraperActionHandler PreMovieImageScrape;
+
+ /// <summary>
+ /// Occurs after movie poster is scraped.
+ /// </summary>
+ public event Events.PostMovieImageScraperActionHandler PostMovieImageScrape;
+
+ #endregion Events
+
+
+ #region Fields
+
+ private static readonly log4net.ILog log = log4net.LogManager.GetLogger(
+ System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ private PluginManager manager;
+
+ #endregion Fields
+
+
+ #region Constructor
+
+ internal MovieScraperManager(PluginManager manager)
+ {
+ this.manager = manager;
+ }
+
+ #endregion Constructor
+
+
+ #region IMovieInfoScraper
+
+ /// <summary>
+ /// Scrapes the movie info.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ public PluginActionResult ScrapeMovieInfo(MovieInfoScraperActionContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+ if (manager.Plugins.Count == 0)
+ return new PluginActionResult();
+
+ if (PreMovieInfoScrape != null)
+ context = PreMovieInfoScrape(context);
+
+ PluginActionResult result = null;
+
+ foreach (IMovieInfoScraper plugin in manager.Plugins
+ .Where(p => p.Enabled && p.Plugin is IMovieInfoScraper)
+ .OrderBy(p => p.Order)
+ .Select(p => p.Plugin))
+ {
+ result = plugin.ScrapeMovieInfo(context);
+ if (result != null && result.BreakChain) break;
+ }
+
+ if (result == null)
+ result = new PluginActionResult();
+
+ if (PostMovieInfoScrape != null)
+ result = PostMovieInfoScrape(result);
+
+ return result;
+ }
+
+ #endregion IMovieInfoScraper
+
+
+ #region IMovieImageScraper
+
+ /// <summary>
+ /// Scrapes the movie posters.
+ /// </summary>
+ /// <param name="context">The context.</param>
+ /// <returns></returns>
+ public PluginActionResult ScrapeMovieImage(MovieImageScraperActionContext context)
+ {
+ if (context == null)
+ throw new ArgumentNullException("context");
+ if (manager.Plugins.Count == 0)
+ return new PluginActionResult();
+
+ if (PreMovieImageScrape != null)
+ context = PreMovieImageScrape(context);
+
+ PluginActionResult result = null;
+
+ foreach (IMovieImageScraper plugin in manager.Plugins
+ .Where(p => p.Enabled && p.Plugin is IMovieImageScraper)
+ .OrderBy(p => p.Order)
+ .Select(p => p.Plugin))
+ {
+ result = plugin.ScrapeMovieImage(context);
+ if (result != null && result.BreakChain) break;
+ }
+
+ if (result == null)
+ result = new PluginActionResult();
+
+ if (PostMovieImageScrape != null)
+ result = PostMovieImageScrape(result);
+
+ return result;
+ }
+
+ #endregion IMovieImageScraper
+
+
+ #region IDisposable
+
+ #region Fields
+
+ private bool disposed = false;
+
+ #endregion
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets a value indicating whether the plug-in manager has been disposed of.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if this instance has been disposed of; otherwise, <c>false</c>.
+ /// </value>
+ public bool IsDisposed
+ {
+ get { return disposed; }
+ }
+
+ #endregion Properties
+
+
+ #region Methods
+
+ /// <summary>
+ /// Releases resources used by this object.
+ /// </summary>
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ /// <summary>
+ /// Releases unmanaged and - optionally - managed resources
+ /// </summary>
+ /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ disposed = true;
+
+ // Free other state (managed objects).
+ foreach (Delegate d in PreMovieInfoScrape.GetInvocationList())
+ PreMovieInfoScrape -= (Events.PreMovieInfoScraperActionHandler)d;
+ foreach (Delegate d in PostMovieInfoScrape.GetInvocationList())
+ PostMovieInfoScrape -= (Events.PostMovieInfoScraperActionHandler)d;
+ }
+
+ // Free your own state (unmanaged objects).
+ // Set large fields to null.
+ }
+
+ /// <summary>
+ /// Releases unmanaged resources and performs other cleanup operations before the
+ /// <see cref="PluginManager"/> is reclaimed by garbage collection.
+ /// </summary>
+ ~MovieScraperManager()
+ {
+ Dispose(false);
+ }
+
+ #endregion Methods
+
+ #endregion IDisposable
+
+ }
+}
79 Ember.Plugins/Scraper/ScraperActionContext.cs
View
@@ -0,0 +1,79 @@
+namespace Ember.Plugins.Scraper
+{
+
+ /// <summary>
+ /// The type of scrape to perform.
+ /// </summary>
+ public enum ScrapeType
+ {
+ /// <summary>
+ /// A manual scraped.
+ /// </summary>
+ Manual,
+
+ /// <summary>
+ /// An automatic scrape.
+ /// </summary>
+ Automatic,
+ }
+
+
+ /// <summary>
+ /// Context for scraper actions.
+ /// </summary>
+ public class ScraperActionContext
+ : PluginActionContext
+ {
+
+ #region Fields
+
+ private ScrapeType scrapeType;
+ private bool askIfMultipleResults;
+
+ #endregion Fields
+
+
+ #region Properties
+
+ /// <summary>
+ /// Gets the type of scrape to perform.
+ /// </summary>
+ /// <value>
+ /// The type of scrape to perform.
+ /// </value>
+ public ScrapeType ScrapeType
+ {
+ get { return scrapeType; }
+ }
+
+ /// <summary>
+ /// Gets a value indicating whether to ask or select the best match if multiple results are returned.
+ /// </summary>
+ /// <value>
+ /// <c>true</c> if the user should be asked to select a movie if multiple results are found; otherwise, <c>false</c>.
+ /// </value>
+ public bool AskIfMultipleResults
+ {
+ get { return askIfMultipleResults; }
+ }
+
+ #endregion Properties
+
+
+ #region Constructor
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="ScraperActionContext"/> class.
+ /// </summary>
+ /// <param name="scrapeType">The type of scrape to perform.</param>
+ /// <param name="askIfMultipleResults">if set to <c>true</c> ask the user to select a movie if multiple results are found.</param>
+ public ScraperActionContext(ScrapeType scrapeType, bool askIfMultipleResults)
+ {
+ this.scrapeType = scrapeType;
+ this.askIfMultipleResults = askIfMultipleResults;
+ }
+
+ #endregion Constructor
+
+ }
+}
56 Ember.Plugins/Utility.cs
View
@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+using System.Linq;
+
+namespace Ember.Plugins
+{
+ /// <summary>
+ /// Utility Methods
+ /// </summary>
+ public static class Utility
+ {
+
+ #region Static Methods
+
+ /// <summary>
+ /// Combines multiple path elements.
+ /// </summary>
+ /// <param name="paths">Paths to combine.</param>
+ /// <returns>The combined path.</returns>
+ public static string CombinePath(params string[] paths)
+ {
+ if (paths == null)
+ throw new ArgumentNullException("paths");
+
+ return paths.Aggregate((current, next) => Path.Combine(current, next));
+ }
+
+ /// <summary>
+ /// Sanitises an IMDb ID.
+ /// </summary>
+ /// <param name="imdbId">The IMDb ID.</param>
+ /// <returns>An IMDb ID in the proper format or an empty string if it's invalid.</returns>
+ /// <remarks>This won't be needed in the future once the EmberAPI code has been cleaned up.</remarks>
+ public static string SanitiseIMDbId(string imdbId)
+ {
+ if (string.IsNullOrEmpty(imdbId) || imdbId.Trim().Length == 0)
+ return string.Empty;
+
+ imdbId = imdbId.Trim();
+ if ("tt".Equals(imdbId))
+ imdbId = string.Empty;
+ else
+ {
+ if (!imdbId.StartsWith("tt"))
+ imdbId = string.Concat("tt", imdbId);
+ if (imdbId.Length != 9)
+ imdbId = string.Empty;
+ }
+
+ return imdbId;
+ }
+
+ #endregion Static Methods
+
+ }
+}
15 Ember.Plugins/app.config
View
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+ <configSections>
+ <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
+ <section name="Ember.Plugins.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+ </sectionGroup>
+ </configSections>
+ <applicationSettings>
+ <Ember.Plugins.Properties.Settings>
+ <setting name="AllowPlugins" serializeAs="String">
+ <value>True</value>
+ </setting>
+ </Ember.Plugins.Properties.Settings>
+ </applicationSettings>
+</configuration>
16 Ember.Plugins/log4net.config
View
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<log4net>
+ <!-- This section contains the log4net configuration settings -->
+
+ <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
+ <layout type="log4net.Layout.PatternLayout" value="%date [%thread] %-5level %logger - %message%newline" />
+ </appender>
+
+ <!-- Setup the root category, add the appenders and set the default level -->
+ <root>
+ <level value="ALL" />
+ <appender-ref ref="ConsoleAppender" />
+ </root>
+
+</log4net>
+
4 Ember.Plugins/packages.config
View
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="log4net" version="2.0.0" targetFramework="net35" />
+</packages>
20 EmberAPI/clsAPIMediaInfo.vb
View
@@ -338,13 +338,21 @@ Public Class MediaInfo
If Not String.IsNullOrEmpty(sFormat) Then
Select Case sFormat.ToLower
Case "dts", "a_dts"
- Select Case sProfile.ToUpper
- Case "MA" 'master audio
- sFormat = "dtsma"
- Case "HRA" 'high resolution
- sFormat = "dtshr"
- End Select
+ If sProfile.ToUpper.Contains("MA") Then
+ sFormat = "dtshd_ma" 'Master Audio
+ ElseIf sProfile.ToUpper.Contains("HRA") Then
+ sFormat = "dtshd_hra" 'high resolution
+ End If
+ 'Select Case sProfile.ToUpper
+ ' Case "MA" 'master audio
+ ' sFormat = "dtsma"
+ ' Case "HRA" 'high resolution
+ ' sFormat = "dtshr"
+ 'End Select
End Select
+ If sFormat.ToLower.Contains("truehd") Then
+ sFormat = "truehd" 'Dolby TrueHD
+ End If
Return AdvancedSettings.GetSetting(String.Concat("AudioFormatConvert:", sFormat.ToLower), sFormat.ToLower)
'Return sFormat
Else
BIN  packages/SharpZipLib.0.86.0/SharpZipLib.0.86.0.nupkg
View
Binary file not shown
BIN  packages/SharpZipLib.0.86.0/lib/11/ICSharpCode.SharpZipLib.dll
View
Binary file not shown
BIN  packages/SharpZipLib.0.86.0/lib/20/ICSharpCode.SharpZipLib.dll
View
Binary file not shown
BIN  packages/SharpZipLib.0.86.0/lib/SL3/SharpZipLib.Silverlight3.dll
View
Binary file not shown
BIN  packages/SharpZipLib.0.86.0/lib/SL4/SharpZipLib.Silverlight4.dll
View
Binary file not shown
BIN  packages/System.Data.SQLite.1.0.81.0/System.Data.SQLite.1.0.81.0.nupkg
View
Binary file not shown
BIN  packages/System.Data.SQLite.1.0.81.0/lib/net20/System.Data.SQLite.Linq.dll
View
Binary file not shown
BIN  packages/System.Data.SQLite.1.0.81.0/lib/net20/System.Data.SQLite.dll
View
Binary file not shown
BIN  packages/System.Data.SQLite.1.0.81.0/lib/net40/System.Data.SQLite.Linq.dll
View
Binary file not shown
BIN  packages/System.Data.SQLite.1.0.81.0/lib/net40/System.Data.SQLite.dll
View
Binary file not shown
1  packages/repositories.config
View
@@ -9,4 +9,5 @@
<repository path="..\Addons\scraper.EmberCore\packages.config" />
<repository path="..\Ember Media Manager\packages.config" />
<repository path="..\EmberAPI\packages.config" />
+ <repository path="..\Ember.Plugins\packages.config" />
</repositories>
Please sign in to comment.
Something went wrong with that request. Please try again.