diff options
206 files changed, 8364 insertions, 5419 deletions
diff --git a/Makefile.in b/Makefile.in index 4feaca8102..885af4ce01 100644 --- a/Makefile.in +++ b/Makefile.in @@ -97,9 +97,6 @@ LIB_DIRS=\ lib/libmodplug \ lib/xbmc-dll-symbols -SS_DIRS=\ - xbmc/screensavers/rsxs-0.9/xbmc - VIS_DIRS=\ xbmc/visualizations/OpenGLSpectrum \ xbmc/visualizations/WaveForm \ @@ -295,8 +292,6 @@ ifeq ($(or $(findstring powerpc-linux,$(ARCH)),$(findstring powerpc64-linux,$(AR $(MAKE) -C xbmc/visualizations/Goom endif endif -screensavers: exports - $(MAKE) -C xbmc/screensavers/rsxs-0.9/xbmc libpython: dllloader $(MAKE) -C xbmc/lib/libPython $(MAKE) -C xbmc/lib/libPython/xbmcmodule diff --git a/addons/libraries/scrapers/AllMusic/description.xml b/addons/libraries/scrapers/AllMusic/description.xml new file mode 100644 index 0000000000..a0ee0d688d --- /dev/null +++ b/addons/libraries/scrapers/AllMusic/description.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>49acf415-02ad-4281-8eb4-9278326f4a05</uuid> + <type>scraper-library</type> + <title>AllMusic</title> + <library>allmusic.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>AllMusic Music Scraper</summary> + <description>Download Music information from www.allmusic.com</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>albums</content> + <content>artists</content> + </supportedcontent> +</addoninfo> diff --git a/addons/libraries/scrapers/DTrailer/description.xml b/addons/libraries/scrapers/DTrailer/description.xml new file mode 100644 index 0000000000..9f8ed800b0 --- /dev/null +++ b/addons/libraries/scrapers/DTrailer/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>79ba05df-14b0-49ba-ad8d-b9eb8cafd038</uuid> + <type>scraper-library</type> + <title>DTrailer</title> + <library>dtrailer.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>DTrailer Scraper Library</summary> + <description>some description</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>movies</content> + </supportedcontent> +</addoninfo> diff --git a/addons/libraries/scrapers/HTBackDrops/description.xml b/addons/libraries/scrapers/HTBackDrops/description.xml new file mode 100644 index 0000000000..d4edaee0a7 --- /dev/null +++ b/addons/libraries/scrapers/HTBackDrops/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>20a6cd29-50f3-41c5-bd96-c9f967138365</uuid> + <type>scraper-library</type> + <title>HTBackdrops</title> + <library>htbackdrops.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>HTBackdrops Scraper Library</summary> + <description>some description</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>movies</content> + </supportedcontent> +</addoninfo> diff --git a/addons/libraries/scrapers/IMDB/description.xml b/addons/libraries/scrapers/IMDB/description.xml new file mode 100644 index 0000000000..30e41f74ed --- /dev/null +++ b/addons/libraries/scrapers/IMDB/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>208d94d7-5c65-4b96-b207-e6b308717623</uuid> + <type>scraper-library</type> + <title>IMDb</title> + <library>imdb.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>IMDB Scraper Library</summary> + <description>Download Movie information from www.imdb.com</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>movies</content> + </supportedcontent> +</addoninfo> diff --git a/addons/libraries/scrapers/IMPA/description.xml b/addons/libraries/scrapers/IMPA/description.xml new file mode 100644 index 0000000000..241110f20f --- /dev/null +++ b/addons/libraries/scrapers/IMPA/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>3cfce449-2e54-4a40-86cc-a6d2199c73b3</uuid> + <type>scraper-library</type> + <title>IMPA</title> + <library>impa.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>IMPA Scraper Library</summary> + <description>some description</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>movies</content> + </supportedcontent> +</addoninfo> diff --git a/addons/libraries/scrapers/LastFM/description.xml b/addons/libraries/scrapers/LastFM/description.xml new file mode 100644 index 0000000000..2c59997bf7 --- /dev/null +++ b/addons/libraries/scrapers/LastFM/description.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addoninfo>
+ <uuid>56e2e02c-1b76-4c91-87bb-0e90b1cb7c72</uuid>
+ <type>scraper-library</type>
+ <title>LastFM</title>
+ <library>lastfm.xml</library>
+ <version>1.0.0</version>
+ <platforms>
+ <platform>all</platform>
+ </platforms>
+ <minversion>
+ <xbmc>20000</xbmc>
+ </minversion>
+ <summary>LastFM Scraper Library</summary>
+ <description>Download Music information</description>
+ <author>TEAMXBMC</author>
+ <supportedcontent>
+ <content>albums</content>
+ <content>artists</content>
+ </supportedcontent>
+</addoninfo>
diff --git a/addons/libraries/scrapers/MoviePosterDB/description.xml b/addons/libraries/scrapers/MoviePosterDB/description.xml new file mode 100644 index 0000000000..079c2ea29f --- /dev/null +++ b/addons/libraries/scrapers/MoviePosterDB/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addoninfo>
+ <uuid>DD60AE50-5D67-4aa9-AF45-A7F2E5518B5F</uuid>
+ <type>scraper-library</type>
+ <title>MoviePostersDB</title>
+ <library>movieposterdb.xml</library>
+ <version>1.0.0</version>
+ <platforms>
+ <platform>all</platform>
+ </platforms>
+ <minversion>
+ <xbmc>20000</xbmc>
+ </minversion>
+ <summary>MoviePosterDB Scraper Library</summary>
+ <description>some desription</description>
+ <author>TEAMXBMC</author>
+ <supportedcontent>
+ <content>movies</content>
+ </supportedcontent>
+</addoninfo>
diff --git a/addons/libraries/scrapers/TMDB/description.xml b/addons/libraries/scrapers/TMDB/description.xml new file mode 100644 index 0000000000..7d469204fc --- /dev/null +++ b/addons/libraries/scrapers/TMDB/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addoninfo>
+ <uuid>52f01b59-f059-4950-a133-dbd778fa9b23</uuid>
+ <type>scraper-library</type>
+ <title>TMDB</title>
+ <library>tmdb.xml</library>
+ <version>1.0.0</version>
+ <platforms>
+ <platform>all</platform>
+ </platforms>
+ <minversion>
+ <xbmc>20000</xbmc>
+ </minversion>
+ <summary>TMDB Scraper Library</summary>
+ <description>some description</description>
+ <author>TEAMXBMC</author>
+ <supportedcontent>
+ <content>movies</content>
+ </supportedcontent>
+</addoninfo>
diff --git a/addons/scrapers/AllMusic/default.tbn b/addons/scrapers/AllMusic/default.tbn Binary files differnew file mode 100644 index 0000000000..30c40ef318 --- /dev/null +++ b/addons/scrapers/AllMusic/default.tbn diff --git a/addons/scrapers/AllMusic/description.xml b/addons/scrapers/AllMusic/description.xml new file mode 100644 index 0000000000..9cdf11fa94 --- /dev/null +++ b/addons/scrapers/AllMusic/description.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>86569F2D-2D5A-4022-8683-4D7CF224BE7B</uuid> + <type>scraper</type> + <title>AllMusic</title> + <library>allmusic.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>AllMusic Music Scraper</summary> + <description>Download Music information from www.allmusic.com</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>albums</content> + <content>artists</content> + </supportedcontent> +</addoninfo> diff --git a/addons/scrapers/AmazonUK/default.tbn b/addons/scrapers/AmazonUK/default.tbn Binary files differnew file mode 100644 index 0000000000..e872b16315 --- /dev/null +++ b/addons/scrapers/AmazonUK/default.tbn diff --git a/addons/scrapers/AmazonUK/description.xml b/addons/scrapers/AmazonUK/description.xml new file mode 100644 index 0000000000..0ffc71a176 --- /dev/null +++ b/addons/scrapers/AmazonUK/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addoninfo>
+ <uuid>F0B735CA-F693-48e6-99DA-B3A66AE56E88</uuid>
+ <type>scraper</type>
+ <title>Amazon UK</title>
+ <library>amazonuk.xml</library>
+ <version>1.0.0</version>
+ <platforms>
+ <platform>all</platform>
+ </platforms>
+ <minversion>
+ <xbmc>20000</xbmc>
+ </minversion>
+ <summary>Amazon Movie Scraper</summary>
+ <description>Download Movie information from www.amazon.uk</description>
+ <author>TEAMXBMC</author>
+ <supportedcontent>
+ <content>movies</content>
+ </supportedcontent>
+</addoninfo>
diff --git a/addons/scrapers/IMDB/default.tbn b/addons/scrapers/IMDB/default.tbn Binary files differnew file mode 100644 index 0000000000..b2edac3fe7 --- /dev/null +++ b/addons/scrapers/IMDB/default.tbn diff --git a/addons/scrapers/IMDB/description.xml b/addons/scrapers/IMDB/description.xml new file mode 100644 index 0000000000..2e6e7e1c0b --- /dev/null +++ b/addons/scrapers/IMDB/description.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>2F2B9322-10BC-46f2-AC4C-72B2E8DD9694</uuid> + <type>scraper</type> + <title>IMDb</title> + <library>imdb.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>IMDB Movie Scraper</summary> + <description>Download Movie information from www.imdb.com</description> + <author>TEAMXBMC</author> + <supportedcontent> + <content>movies</content> + <content>musicvideos</content> + </supportedcontent> +</addoninfo> diff --git a/addons/scrapers/IMDB/resources/language/English/strings.xml b/addons/scrapers/IMDB/resources/language/English/strings.xml new file mode 100644 index 0000000000..7fc277917e --- /dev/null +++ b/addons/scrapers/IMDB/resources/language/English/strings.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<strings> + <!-- settings labels --> + <string id="30000">Enable Full Cast Credits</string> + <string id="30001">Enable IMPAwards</string> + <string id="30002">Enable MoviePosterDB</string> + <string id="30003">Enable Trailer</string> + <string id="30004">Enable Fanart</string> + <string id="30005">IMDB Poster &amp; Actor Thumb(s) Size</string> + <string id="30006">Input Alternative IMDb Source</string> +</strings> + diff --git a/addons/scrapers/LastFM/default.tbn b/addons/scrapers/LastFM/default.tbn Binary files differnew file mode 100644 index 0000000000..b4b14bf354 --- /dev/null +++ b/addons/scrapers/LastFM/default.tbn diff --git a/addons/scrapers/LastFM/description.xml b/addons/scrapers/LastFM/description.xml new file mode 100644 index 0000000000..4b04d1c8b8 --- /dev/null +++ b/addons/scrapers/LastFM/description.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>DD60AE50-5D67-4aa9-AF45-A7F2E5518B5F</uuid> + <type>scraper</type> + <title>LastFM</title> + <library>lastfm.xml</library> + <version>1.0.0</version> + <platforms> + <platform>all</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>LastFM Music Scraper</summary> + <description>Download Music information</description> + <author>TEAMXBMC</author> + <dependencies> + <dependency minversion="1.0.0" maxversion="">56e2e02c-1b76-4c91-87bb-0e90b1cb7c72</dependency> + </dependencies> + <supportedcontent> + <content>albums</content> + <content>artists</content> + </supportedcontent> +</addoninfo> diff --git a/addons/scrapers/YahooMusic/default.tbn b/addons/scrapers/YahooMusic/default.tbn Binary files differnew file mode 100644 index 0000000000..007c422028 --- /dev/null +++ b/addons/scrapers/YahooMusic/default.tbn diff --git a/addons/scrapers/YahooMusic/description.xml b/addons/scrapers/YahooMusic/description.xml new file mode 100644 index 0000000000..0e0243604d --- /dev/null +++ b/addons/scrapers/YahooMusic/description.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<addoninfo>
+ <uuid>EA0E975F-F57F-467a-B77B-2A9CC597873B</uuid>
+ <type>scraper</type>
+ <title>Yahoo! Music</title>
+ <library>yahoomusic.xml</library>
+ <version>1.0.0</version>
+ <platforms>
+ <platform>all</platform>
+ </platforms>
+ <minversion>
+ <xbmc>20000</xbmc>
+ </minversion>
+ <summary>Yahoo! Music Video Scraper</summary>
+ <description>Download Music Video information</description>
+ <author>TEAMXBMC</author>
+ <supportedcontent>
+ <content>musicvideos</content>
+ </supportedcontent>
+</addoninfo>
diff --git a/addons/scrapers/YahooMusic/resources/language/English/strings.xml b/addons/scrapers/YahooMusic/resources/language/English/strings.xml new file mode 100644 index 0000000000..169bc00a9a --- /dev/null +++ b/addons/scrapers/YahooMusic/resources/language/English/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<strings>
+ <!-- settings labels -->
+ <string id="30000">Thumbnail Size</string>
+</strings>
diff --git a/addons/visualizations/GLSpectrum/default.tbn b/addons/visualizations/GLSpectrum/default.tbn Binary files differnew file mode 100755 index 0000000000..fd535ff4e3 --- /dev/null +++ b/addons/visualizations/GLSpectrum/default.tbn diff --git a/addons/visualizations/GLSpectrum/description.xml b/addons/visualizations/GLSpectrum/description.xml new file mode 100644 index 0000000000..1de970f317 --- /dev/null +++ b/addons/visualizations/GLSpectrum/description.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>7A4551D9-2F50-4173-B224-EE209FC9EB1F</uuid> + <type>visualization</type> + <title>OpenGL Spectrum</title> + <library>opengl_spectrum.vis</library> + <librarywin32>opengl_spectrum_win32.vis</librarywin32> + <version>1.0.0</version> + <platforms> + <platform>linux</platform> + <platform>windows</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>OpenGL Visualization</summary> + <description>Visualisation showing a rotating 3D Spectrum Analyzer</description> + <author>TEAMXBMC</author> +</addoninfo> diff --git a/addons/visualizations/GLSpectrum/resources/language/English/strings.xml b/addons/visualizations/GLSpectrum/resources/language/English/strings.xml new file mode 100644 index 0000000000..17f5d723ad --- /dev/null +++ b/addons/visualizations/GLSpectrum/resources/language/English/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<strings> + <!-- settings labels --> + <string id="30000">Mode</string> + <string id="30001">Filled</string> + <string id="30002">Wireframe</string> + <string id="30003">Points</string> + <string id="30004">Bar Height</string> + <string id="30005">Small</string> + <string id="30006">Default</string> + <string id="30007">Big</string> + <string id="30008">Very Big</string> + <string id="30009">Speed</string> + <string id="30010">Very Slow</string> + <string id="30011">Slow</string> + <string id="30012">Default</string> + <string id="30013">Fast</string> + <string id="30014">Very Fast</string> +</strings> diff --git a/addons/visualizations/GLSpectrum/resources/language/German/strings.xml b/addons/visualizations/GLSpectrum/resources/language/German/strings.xml new file mode 100644 index 0000000000..f40aa61ebc --- /dev/null +++ b/addons/visualizations/GLSpectrum/resources/language/German/strings.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<strings> + <!-- settings labels --> + <string id="30000">Balkenhöhe</string> + <string id="30001">Standart</string> + <string id="30002">Groß</string> + <string id="30003">Sehr groß</string> + <string id="30004">Klein</string> + <string id="30005">Modus</string> + <string id="30006">Ausgefüllt</string> + <string id="30007">Drahtgeflecht</string> + <string id="30008">Punkte</string> + <string id="30009">Geschwindigkeit</string> + <string id="30010">Standart</string> + <string id="30011">Langsam</string> + <string id="30012">Sehr langsam</string> + <string id="30013">Schnell</string> + <string id="30014">Sehr schnell</string> +</strings> diff --git a/addons/visualizations/GLSpectrum/resources/settings.xml b/addons/visualizations/GLSpectrum/resources/settings.xml new file mode 100644 index 0000000000..a2c2cf7d61 --- /dev/null +++ b/addons/visualizations/GLSpectrum/resources/settings.xml @@ -0,0 +1,5 @@ +<settings> +<setting id="mode" label="30000" type="enum" lvalues="30001|30002|30003" default="0"/> +<setting id="bar_height" label="30004" type="enum" lvalues="30005|30006|30007|30008" default="1"/> +<setting id="speed" label="30009" type="enum" lvalues="30010|30011|30012|30013|30014" default="2"/> +</settings> diff --git a/addons/visualizations/ProjectM/default.tbn b/addons/visualizations/ProjectM/default.tbn Binary files differnew file mode 100644 index 0000000000..67e150d035 --- /dev/null +++ b/addons/visualizations/ProjectM/default.tbn diff --git a/addons/visualizations/ProjectM/description.xml b/addons/visualizations/ProjectM/description.xml new file mode 100644 index 0000000000..b154a3a9b6 --- /dev/null +++ b/addons/visualizations/ProjectM/description.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>b67a5960-d956-11de-8a39-0800200c9a66</uuid> + <type>visualization</type> + <title>projectM</title> + <library>projectM.vis</library> + <librarywin32>projectM_win32.vis</librarywin32> + <version>1.0.0</version> + <platforms> + <platform>linux</platform> + <platform>windows</platform> + </platforms> + <minversion> + <xbmc>25000</xbmc> + </minversion> + <summary>projectM Visualization</summary> + <description>projectM is an LGPL'ed reimplementation of Milkdrop under OpenGL</description> + <author>TEAMXBMC</author> +</addoninfo> diff --git a/addons/visualizations/ProjectM/resources/language/English/strings.xml b/addons/visualizations/ProjectM/resources/language/English/strings.xml new file mode 100644 index 0000000000..eccbdfc0da --- /dev/null +++ b/addons/visualizations/ProjectM/resources/language/English/strings.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes"?> +<strings> + <!-- settings labels --> + <string id="30000">Render Quality</string> + <string id="30001">Low</string> + <string id="30002">Medium</string> + <string id="30003">High</string> + <string id="30004">Maximum</string> + <string id="30005">Shuffle Mode</string> + <string id="30006">Smooth Preset Duration</string> + <string id="30007">Preset Duration</string> + <string id="30008">Beat Sensitivity</string> +</strings> diff --git a/addons/visualizations/ProjectM/resources/presets.zip b/addons/visualizations/ProjectM/resources/presets.zip Binary files differnew file mode 100644 index 0000000000..9ad08b4f40 --- /dev/null +++ b/addons/visualizations/ProjectM/resources/presets.zip diff --git a/addons/visualizations/Waveform/default.tbn b/addons/visualizations/Waveform/default.tbn Binary files differnew file mode 100755 index 0000000000..7d5974fd57 --- /dev/null +++ b/addons/visualizations/Waveform/default.tbn diff --git a/addons/visualizations/Waveform/description.xml b/addons/visualizations/Waveform/description.xml new file mode 100644 index 0000000000..55f5082240 --- /dev/null +++ b/addons/visualizations/Waveform/description.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>9AFC128B-A6B6-4824-9BC4-B122966709B3</uuid> + <type>visualization</type> + <title>Waveform</title> + <library>Waveform.vis</library> + <librarywin32>Waveform_win32.vis</librarywin32> + <version>1.0.0</version> + <platforms> + <platform>linux</platform> + <platform>windows</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>Visualization</summary> + <description>Visualization showing a Waveform Graph</description> + <author>MrC</author> +</addoninfo> diff --git a/addons/visualizations/iTunes/description.xml b/addons/visualizations/iTunes/description.xml new file mode 100644 index 0000000000..cadfe4b690 --- /dev/null +++ b/addons/visualizations/iTunes/description.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<addoninfo> + <uuid>57675d11-0ae3-11df-8a39-0800200c9a66</uuid> + <type>visualization</type> + <title>iTunes Visualization</title> + <library>iTunes.mvis</library> + <version>1.0.0</version> + <platforms> + <platform>osx</platform> + </platforms> + <minversion> + <xbmc>20000</xbmc> + </minversion> + <summary>iTunes Visualization Wrapper</summary> + <description>Some description</description> + <author>TEAMXBMC</author> +</addoninfo> diff --git a/guilib/GUIControl.h b/guilib/GUIControl.h index f7408e6784..ab98f5a7f9 100644 --- a/guilib/GUIControl.h +++ b/guilib/GUIControl.h @@ -235,6 +235,7 @@ public: GUICONTROL_CONSOLE, GUICONTROL_EDIT, GUICONTROL_VISUALISATION, + GUICONTROL_RENDERADDON, GUICONTROL_MULTI_IMAGE, GUICONTROL_GROUP, GUICONTROL_GROUPLIST, diff --git a/guilib/GUIInfoTypes.cpp b/guilib/GUIInfoTypes.cpp index a8212830d0..473cc0a495 100644 --- a/guilib/GUIInfoTypes.cpp +++ b/guilib/GUIInfoTypes.cpp @@ -22,6 +22,7 @@ #include "GUIInfoTypes.h" #include "utils/CharsetConverter.h" #include "utils/GUIInfoManager.h" +#include "utils/AddonManager.h" #include "utils/log.h" #include "LocalizeStrings.h" #include "GUIColorManager.h" @@ -29,6 +30,7 @@ #include "StringUtils.h" using namespace std; +using ADDON::CAddonMgr; CGUIInfoBool::CGUIInfoBool(bool value) { @@ -221,12 +223,41 @@ CStdString CGUIInfoLabel::ReplaceLocalize(const CStdString &label) return work; } +CStdString CGUIInfoLabel::ReplaceAddonStrings(const CStdString &label) +{ + CStdString work(label); + // Replace all $ADDON[uuid number] with the real string + int pos1 = work.Find("$ADDON["); + while (pos1 >= 0) + { + int pos2 = StringUtils::FindEndBracket(work, '[', ']', pos1 + 7); + if (pos2 > pos1) + { + CStdString left = work.Left(pos1); + CStdString right = work.Mid(pos2 + 1); + CStdString uuid = work.substr(pos1+7, 36); + int stringid = atoi(work.substr(pos1+7+36+1, 5).c_str()); + CStdString replace = CAddonMgr::Get()->GetString(uuid, stringid); + work = left + replace + right; + } + else + { + CLog::Log(LOGERROR, "Error parsing label - missing ']'"); + return ""; + } + pos1 = work.Find("$ADDON[", pos1); + } + return work; +} + void CGUIInfoLabel::Parse(const CStdString &label) { m_info.clear(); // Step 1: Replace all $LOCALIZE[number] with the real string CStdString work = ReplaceLocalize(label); - // Step 2: Find all $INFO[info,prefix,postfix] blocks + // Step 2: Replace all $ADDON[uuid number] with the real string + work = ReplaceAddonStrings(work); + // Step 3: Find all $INFO[info,prefix,postfix] blocks int pos1 = work.Find("$INFO["); while (pos1 >= 0) { diff --git a/guilib/GUIInfoTypes.h b/guilib/GUIInfoTypes.h index 3ceb7dbd0f..115bb85343 100644 --- a/guilib/GUIInfoTypes.h +++ b/guilib/GUIInfoTypes.h @@ -89,6 +89,13 @@ public: */ static CStdString ReplaceLocalize(const CStdString &label); + /*! + \brief Replaces instances of $ADDON[uuid number] with the appropriate localized addon string + \param label text to replace + \return text with any localized strings filled in. + */ + static CStdString ReplaceAddonStrings(const CStdString &label); + private: void Parse(const CStdString &label); diff --git a/guilib/GUIMessage.cpp b/guilib/GUIMessage.cpp index 6a08bd36b5..437aa9ff4f 100644 --- a/guilib/GUIMessage.cpp +++ b/guilib/GUIMessage.cpp @@ -57,16 +57,6 @@ CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int p m_item = item; } -CGUIMessage::CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CVisualisation* vis) -{ - m_message = msg; - m_senderID = senderID; - m_controlID = controlID; - m_param1 = param1; - m_param2 = param2; - m_pointer = vis; -} - CGUIMessage::CGUIMessage(const CGUIMessage& msg) { *this = msg; diff --git a/guilib/GUIMessage.h b/guilib/GUIMessage.h index 7efca3ec93..395f868584 100644 --- a/guilib/GUIMessage.h +++ b/guilib/GUIMessage.h @@ -257,7 +257,6 @@ do { \ // forwards class CGUIListItem; typedef boost::shared_ptr<CGUIListItem> CGUIListItemPtr; class CFileItemList; -class CVisualisation; /*! \ingroup winmsg @@ -269,7 +268,6 @@ public: CGUIMessage(int dwMsg, int senderID, int controlID, int param1 = 0, int param2 = 0); CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CFileItemList* item); CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, const CGUIListItemPtr &item); - CGUIMessage(int msg, int senderID, int controlID, int param1, int param2, CVisualisation* vis); CGUIMessage(const CGUIMessage& msg); virtual ~CGUIMessage(void); const CGUIMessage& operator = (const CGUIMessage& msg); diff --git a/guilib/GUIRenderingControl.cpp b/guilib/GUIRenderingControl.cpp new file mode 100644 index 0000000000..03ad6e1620 --- /dev/null +++ b/guilib/GUIRenderingControl.cpp @@ -0,0 +1,92 @@ +#include "GUIRenderingControl.h" +#include "GUIUserMessages.h" +#include "visualizations/Visualisation.h" +#include "utils/SingleLock.h" + +using namespace std; +using namespace ADDON; + +#define LABEL_ROW1 10 +#define LABEL_ROW2 11 +#define LABEL_ROW3 12 + +CGUIRenderingControl::CGUIRenderingControl(int parentID, int controlID, float posX, float posY, float width, float height) + : CGUIControl(parentID, controlID, posX, posY, width, height) +{ + ControlType = GUICONTROL_RENDERADDON; +} + +CGUIRenderingControl::CGUIRenderingControl(const CGUIRenderingControl &from) +: CGUIControl(from) +{ + ControlType = GUICONTROL_RENDERADDON; +} + +void CGUIRenderingControl::LoadAddon(const AddonPtr &addon) +{ + if (!addon) + return; + + CSingleLock lock(m_rendering); + g_graphicsContext.CaptureStateBlock(); + float x = g_graphicsContext.ScaleFinalXCoord(GetXPosition(), GetYPosition()); + float y = g_graphicsContext.ScaleFinalYCoord(GetXPosition(), GetYPosition()); + float w = g_graphicsContext.ScaleFinalXCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - x; + float h = g_graphicsContext.ScaleFinalYCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - y; + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x + w > g_graphicsContext.GetWidth()) w = g_graphicsContext.GetWidth() - x; + if (y + h > g_graphicsContext.GetHeight()) h = g_graphicsContext.GetHeight() - y; + + VizPtr viz = boost::dynamic_pointer_cast<CVisualisation>(addon); + if (viz && viz->Create((int)(x+0.5f), (int)(y+0.5f), (int)(w+0.5f), (int)(h+0.5f))) + { + m_addon = viz; + } + + g_graphicsContext.ApplyStateBlock(); + VerifyGLState(); +} + +void CGUIRenderingControl::UpdateVisibility(const CGUIListItem *item) +{ + // if made invisible, start timer, only free addonptr after + // some period, configurable by window class + CGUIControl::UpdateVisibility(item); + if (!IsVisible() && m_addon) + FreeResources(); +} + +void CGUIRenderingControl::Render() +{ + CSingleLock lock(m_rendering); + if (m_addon) + { + // set the viewport - note: We currently don't have any control over how + // the addon renders, so the best we can do is attempt to define + // a viewport?? + g_graphicsContext.SetViewPort(m_posX, m_posY, m_width, m_height); + g_graphicsContext.CaptureStateBlock(); + m_addon->Render(); + g_graphicsContext.ApplyStateBlock(); + g_graphicsContext.RestoreViewPort(); + } + + CGUIControl::Render(); +} + +void CGUIRenderingControl::FreeResources() +{ + if (!m_addon) return; + + CSingleLock lock(m_rendering); + g_graphicsContext.CaptureStateBlock(); //TODO locking + m_addon->Stop(); + g_graphicsContext.ApplyStateBlock(); + m_addon.reset(); +} + +bool CGUIRenderingControl::CanFocusFromPoint(const CPoint &point) const +{ // mouse is allowed to focus this control, but it doesn't actually receive focus + return IsVisible() && HitTest(point); +} diff --git a/guilib/GUIRenderingControl.h b/guilib/GUIRenderingControl.h new file mode 100644 index 0000000000..639f36182a --- /dev/null +++ b/guilib/GUIRenderingControl.h @@ -0,0 +1,43 @@ +#pragma once +/* + * Copyright (C) 2005-2010 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "GUIControl.h" +#include "IAddon.h" + +class CGUIRenderingControl : public CGUIControl +{ +public: + CGUIRenderingControl(int parentID, int controlID, float posX, float posY, float width, float height); + CGUIRenderingControl(const CGUIRenderingControl &from); + virtual CGUIRenderingControl *Clone() const { return new CGUIRenderingControl(*this); }; //TODO check for naughties + + virtual void Render(); + virtual void UpdateVisibility(const CGUIListItem *item = NULL); + virtual void FreeResources(); + virtual bool CanFocus() const { return false; } + virtual bool CanFocusFromPoint(const CPoint &point) const; + void LoadAddon(const ADDON::AddonPtr &addon); + +protected: + CCriticalSection m_rendering; + ADDON::VizPtr m_addon; +}; diff --git a/guilib/GUIVisualisationControl.cpp b/guilib/GUIVisualisationControl.cpp index 0783c866d7..a7569bde84 100644 --- a/guilib/GUIVisualisationControl.cpp +++ b/guilib/GUIVisualisationControl.cpp @@ -2,473 +2,50 @@ #include "GUIWindowManager.h" #include "GUIUserMessages.h" #include "Application.h" -#include "visualizations/Visualisation.h" -#include "visualizations/VisualisationFactory.h" -#include "visualizations/fft.h" -#include "Util.h" -#include "utils/CriticalSection.h" +#include "utils/AddonManager.h" #include "utils/log.h" -#include "utils/SingleLock.h" -#include "utils/GUIInfoManager.h" -#include "GUISettings.h" -#include "FileSystem/SpecialProtocol.h" using namespace std; -using namespace MUSIC_INFO; +using namespace ADDON; #define LABEL_ROW1 10 #define LABEL_ROW2 11 #define LABEL_ROW3 12 -// uggly hack, we can only allow one visualisation at one time or stuff starts crashing -static CCriticalSection m_critSection; -static bool m_globalvis = false; - -CAudioBuffer::CAudioBuffer(int iSize) -{ - m_iLen = iSize; - m_pBuffer = new short[iSize]; -} - -CAudioBuffer::~CAudioBuffer() -{ - delete [] m_pBuffer; -} - -const short* CAudioBuffer::Get() const -{ - return m_pBuffer; -} - -void CAudioBuffer::Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample) -{ - if (iSize<0) - { - return; - } - - if (iBitsPerSample == 16) - { - iSize /= 2; - for (int i = 0; i < iSize && i < m_iLen; i++) - { // 16 bit -> convert to short directly - m_pBuffer[i] = ((short *)psBuffer)[i]; - } - } - else if (iBitsPerSample == 8) - { - for (int i = 0; i < iSize && i < m_iLen; i++) - { // 8 bit -> convert to signed short by multiplying by 256 - m_pBuffer[i] = ((short)((char *)psBuffer)[i]) << 8; - } - } - else // assume 24 bit data - { - iSize /= 3; - for (int i = 0; i < iSize && i < m_iLen; i++) - { // 24 bit -> ignore least significant byte and convert to signed short - m_pBuffer[i] = (((int)psBuffer[3 * i + 1]) << 0) + (((int)((char *)psBuffer)[3 * i + 2]) << 8); - } - } - for (int i = iSize; i < m_iLen;++i) m_pBuffer[i] = 0; -} - CGUIVisualisationControl::CGUIVisualisationControl(int parentID, int controlID, float posX, float posY, float width, float height) - : CGUIControl(parentID, controlID, posX, posY, width, height) + : CGUIRenderingControl(parentID, controlID, posX, posY, width, height) { - m_pVisualisation = NULL; - m_bInitialized = false; - m_iNumBuffers = 0; - m_currentVis = ""; ControlType = GUICONTROL_VISUALISATION; } CGUIVisualisationControl::CGUIVisualisationControl(const CGUIVisualisationControl &from) -: CGUIControl(from) +: CGUIRenderingControl(from) { - m_pVisualisation = NULL; - m_bInitialized = false; - m_iNumBuffers = 0; - m_currentVis = ""; ControlType = GUICONTROL_VISUALISATION; } -CGUIVisualisationControl::~CGUIVisualisationControl(void) -{ -} - -void CGUIVisualisationControl::FreeVisualisation() -{ - if (!m_bInitialized) return; - m_bInitialized = false; - // tell our app that we're going - CGUIMessage msg(GUI_MSG_VISUALISATION_UNLOADING, 0, 0); - g_windowManager.SendMessage(msg); - - CSingleLock lock (m_critSection); - - CLog::Log(LOGDEBUG, "FreeVisualisation() started"); - if (g_application.m_pPlayer) - g_application.m_pPlayer->UnRegisterAudioCallback(); - if (m_pVisualisation) - { - OutputDebugString("Visualisation::Stop()\n"); - g_graphicsContext.CaptureStateBlock(); - m_pVisualisation->Stop(); - g_graphicsContext.ApplyStateBlock(); - - OutputDebugString("delete Visualisation()\n"); - delete m_pVisualisation; - - /* we released the global vis spot */ - m_globalvis = false; - } - m_pVisualisation = NULL; - ClearBuffers(); - CLog::Log(LOGDEBUG, "FreeVisualisation() done"); -} - -void CGUIVisualisationControl::LoadVisualisation() -{ - CSingleLock lock (m_critSection); - if (m_pVisualisation) - FreeVisualisation(); - - m_bInitialized = false; - - /* check if any other control beat us to the punch */ - if(m_globalvis) - return; - - CVisualisationFactory factory; - CStdString strVisz; - m_currentVis = g_guiSettings.GetString("musicplayer.visualisation"); - - if (m_currentVis.Equals("None")) - return; - - // check if it's a multi-vis and if it is , get it's module name - { - int colonPos = m_currentVis.ReverseFind(":"); - if ( colonPos > 0 ) - { - CStdString strModule = m_currentVis.Mid( colonPos+1 ); - strVisz = m_currentVis.Mid( 0, colonPos ); - m_pVisualisation = factory.LoadVisualisation(strVisz, strModule); - } - else - { - strVisz = m_currentVis; - m_pVisualisation = factory.LoadVisualisation(strVisz); - } - } - if (m_pVisualisation) - { - g_graphicsContext.CaptureStateBlock(); - float x = g_graphicsContext.ScaleFinalXCoord(GetXPosition(), GetYPosition()); - float y = g_graphicsContext.ScaleFinalYCoord(GetXPosition(), GetYPosition()); - float w = g_graphicsContext.ScaleFinalXCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - x; - float h = g_graphicsContext.ScaleFinalYCoord(GetXPosition() + GetWidth(), GetYPosition() + GetHeight()) - y; - if (x < 0) x = 0; - if (y < 0) y = 0; - if (x + w > g_graphicsContext.GetWidth()) w = g_graphicsContext.GetWidth() - x; - if (y + h > g_graphicsContext.GetHeight()) h = g_graphicsContext.GetHeight() - y; - - m_pVisualisation->Create((int)(x+0.5f), (int)(y+0.5f), (int)(w+0.5f), (int)(h+0.5f)); - g_graphicsContext.ApplyStateBlock(); - VerifyGLState(); - if (g_application.m_pPlayer) - g_application.m_pPlayer->RegisterAudioCallback(this); - - // Create new audio buffers - CreateBuffers(); - - m_globalvis = true; - } - - // tell our app that we're back - CGUIMessage msg(GUI_MSG_VISUALISATION_LOADED, 0, 0, 0, 0, m_pVisualisation); - g_windowManager.SendMessage(msg); -} - -void CGUIVisualisationControl::UpdateVisibility(const CGUIListItem *item) -{ - CGUIControl::UpdateVisibility(item); - if (!IsVisible() && m_bInitialized) - FreeVisualisation(); -} - -void CGUIVisualisationControl::SetInvalid() -{ - FreeResources(); -} - void CGUIVisualisationControl::Render() { - if (m_pVisualisation == NULL) - { // check if we need to load - if (g_application.IsPlayingAudio()) - { - LoadVisualisation(); - } - CGUIControl::Render(); - - return; - } - else - { // check if we need to unload - if (!g_application.IsPlayingAudio()) - { // deinit - FreeVisualisation(); - CGUIControl::Render(); - return; - } - else if (!m_currentVis.Equals(g_guiSettings.GetString("musicplayer.visualisation"))) - { // vis changed - reload - LoadVisualisation(); - - CGUIControl::Render(); - - return; - } - } - CSingleLock lock (m_critSection); - if (m_pVisualisation) - { - if (m_bInitialized) - { - // set the viewport - note: We currently don't have any control over how - // the visualisation renders, so the best we can do is attempt to define - // a viewport?? - g_graphicsContext.SetViewPort(m_posX, m_posY, m_width, m_height); - try - { - g_graphicsContext.CaptureStateBlock(); - m_pVisualisation->Render(); - g_graphicsContext.ApplyStateBlock(); - } - catch (...) - { - CLog::Log(LOGERROR, "Exception in Visualisation::Render()"); - } - // clear the viewport - g_graphicsContext.RestoreViewPort(); - } - } - - CGUIControl::Render(); -} - - -void CGUIVisualisationControl::OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample) -{ - CSingleLock lock (m_critSection); - if (!m_pVisualisation) - return ; - CLog::Log(LOGDEBUG, "OnInitialize() started"); - - m_iChannels = iChannels; - m_iSamplesPerSec = iSamplesPerSec; - m_iBitsPerSample = iBitsPerSample; - - // Start the visualisation (this loads settings etc.) - CStdString strFile = CUtil::GetFileName(g_application.CurrentFile()); - OutputDebugString("Visualisation::Start()\n"); - m_pVisualisation->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile); - if (!m_bInitialized) + if (!m_addon && g_application.IsPlayingAudio()) { - UpdateTrack(); - } - m_bInitialized = true; - CLog::Log(LOGDEBUG, "OnInitialize() done"); -} - -void CGUIVisualisationControl::OnAudioData(const unsigned char* pAudioData, int iAudioDataLength) -{ - CSingleLock lock (m_critSection); - if (!m_pVisualisation) - return ; - if (!m_bInitialized) return ; - - // FIXME: iAudioDataLength should never be less than 0 - if (iAudioDataLength<0) - return; - - // Save our audio data in the buffers - auto_ptr<CAudioBuffer> pBuffer ( new CAudioBuffer(2*AUDIO_BUFFER_SIZE) ); - pBuffer->Set(pAudioData, iAudioDataLength, m_iBitsPerSample); - m_vecBuffers.push_back( pBuffer.release() ); - - if ( (int)m_vecBuffers.size() < m_iNumBuffers) return ; - - auto_ptr<CAudioBuffer> ptrAudioBuffer ( m_vecBuffers.front() ); - m_vecBuffers.pop_front(); - // Fourier transform the data if the vis wants it... - if (m_bWantsFreq) - { - // Convert to floats - const short* psAudioData = ptrAudioBuffer->Get(); - for (int i = 0; i < 2*AUDIO_BUFFER_SIZE; i++) - { - m_fFreq[i] = (float)psAudioData[i]; - } - - // FFT the data - twochanwithwindow(m_fFreq, AUDIO_BUFFER_SIZE); - - // Normalize the data - float fMinData = (float)AUDIO_BUFFER_SIZE * AUDIO_BUFFER_SIZE * 3 / 8 * 0.5 * 0.5; // 3/8 for the Hann window, 0.5 as minimum amplitude - float fInvMinData = 1.0f/fMinData; - for (int i = 0; i < AUDIO_BUFFER_SIZE + 2; i++) - { - m_fFreq[i] *= fInvMinData; - } - - // Transfer data to our visualisation - try - { - m_pVisualisation->AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, m_fFreq, AUDIO_BUFFER_SIZE); - } - catch (...) - { - CLog::Log(LOGERROR, "Exception in Visualisation::AudioData()"); - } + AddonPtr viz; + if (ADDON::CAddonMgr::Get()->GetDefault(ADDON_VIZ, viz)) + LoadAddon(viz); } else - { // Transfer data to our visualisation - try - { - m_pVisualisation->AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, NULL, 0); - } - catch (...) - { - CLog::Log(LOGERROR, "Exception in Visualisation::AudioData()"); - } - } - return ; -} - -bool CGUIVisualisationControl::OnAction(const CAction &action) -{ - if (!m_pVisualisation) return false; - enum CVisualisation::VIS_ACTION visAction = CVisualisation::VIS_ACTION_NONE; - if (action.GetID() == ACTION_VIS_PRESET_NEXT) - visAction = CVisualisation::VIS_ACTION_NEXT_PRESET; - else if (action.GetID() == ACTION_VIS_PRESET_PREV) - visAction = CVisualisation::VIS_ACTION_PREV_PRESET; - else if (action.GetID() == ACTION_VIS_PRESET_LOCK) - visAction = CVisualisation::VIS_ACTION_LOCK_PRESET; - else if (action.GetID() == ACTION_VIS_PRESET_RANDOM) - visAction = CVisualisation::VIS_ACTION_RANDOM_PRESET; - else if (action.GetID() == ACTION_VIS_RATE_PRESET_PLUS) - visAction = CVisualisation::VIS_ACTION_RATE_PRESET_PLUS; - else if (action.GetID() == ACTION_VIS_RATE_PRESET_MINUS) - visAction = CVisualisation::VIS_ACTION_RATE_PRESET_MINUS; - - return m_pVisualisation->OnAction(visAction); -} - -bool CGUIVisualisationControl::UpdateTrack() -{ - bool handled = false; - - if ( m_pVisualisation ) - { - // get the current album art filename - m_AlbumThumb = _P(g_infoManager.GetImage(MUSICPLAYER_COVER, WINDOW_INVALID)); - - // get the current track tag - const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag(); - - if (m_AlbumThumb == "DefaultAlbumCover.png") - m_AlbumThumb = ""; - else - CLog::Log(LOGDEBUG,"Updating visualisation albumart: %s", m_AlbumThumb.c_str()); - - // inform the visulisation of the current album art - if ( m_pVisualisation->OnAction( CVisualisation::VIS_ACTION_UPDATE_ALBUMART, - (void*)( m_AlbumThumb.c_str() ) ) ) - handled = true; - - // inform the visualisation of the current track's tag information - if ( tag && m_pVisualisation->OnAction( CVisualisation::VIS_ACTION_UPDATE_TRACK, - (void*)tag ) ) - handled = true; - } - return handled; -} - -bool CGUIVisualisationControl::OnMessage(CGUIMessage &message) -{ - if (message.GetMessage() == GUI_MSG_GET_VISUALISATION) - { - message.SetPointer(GetVisualisation()); - return true; - } - else if (message.GetMessage() == GUI_MSG_VISUALISATION_ACTION) - { - return OnAction(CAction(message.GetParam1())); - } - else if (message.GetMessage() == GUI_MSG_PLAYBACK_STARTED) - { - if (IsVisible() && UpdateTrack()) return true; - } - return CGUIControl::OnMessage(message); -} - -void CGUIVisualisationControl::CreateBuffers() -{ - CSingleLock lock (m_critSection); - ClearBuffers(); - - // Get the number of buffers from the current vis - VIS_INFO info; - m_pVisualisation->GetInfo(&info); - m_iNumBuffers = info.iSyncDelay + 1; - m_bWantsFreq = info.bWantsFreq; - if (m_iNumBuffers > MAX_AUDIO_BUFFERS) - m_iNumBuffers = MAX_AUDIO_BUFFERS; - if (m_iNumBuffers < 1) - m_iNumBuffers = 1; -} - - -void CGUIVisualisationControl::ClearBuffers() -{ - CSingleLock lock (m_critSection); - m_bWantsFreq = false; - m_iNumBuffers = 0; - - while (m_vecBuffers.size() > 0) - { - CAudioBuffer* pAudioBuffer = m_vecBuffers.front(); - delete pAudioBuffer; - m_vecBuffers.pop_front(); - } - for (int j = 0; j < AUDIO_BUFFER_SIZE*2; j++) - { - m_fFreq[j] = 0.0f; - } + CGUIRenderingControl::Render(); } void CGUIVisualisationControl::FreeResources() { - FreeVisualisation(); - CGUIControl::FreeResources(); -} - -CVisualisation *CGUIVisualisationControl::GetVisualisation() -{ - CSingleLock lock (m_critSection); - return m_pVisualisation; -} + // tell our app that we're going + if (!m_addon) + return; -bool CGUIVisualisationControl::CanFocus() const -{ // unfocusable - return false; + CGUIMessage msg(GUI_MSG_VISUALISATION_UNLOADING, m_controlID, 0); + g_windowManager.SendMessage(msg); + CLog::Log(LOGDEBUG, "FreeVisualisation() started"); + CGUIRenderingControl::FreeResources(); + CLog::Log(LOGDEBUG, "FreeVisualisation() done"); } -bool CGUIVisualisationControl::CanFocusFromPoint(const CPoint &point) const -{ // mouse is allowed to focus this control, but it doesn't actually receive focus - return IsVisible() && HitTest(point); -} diff --git a/guilib/GUIVisualisationControl.h b/guilib/GUIVisualisationControl.h index af06adac68..e782f6a945 100644 --- a/guilib/GUIVisualisationControl.h +++ b/guilib/GUIVisualisationControl.h @@ -1,5 +1,4 @@ #pragma once - /* * Copyright (C) 2005-2008 Team XBMC * http://www.xbmc.org @@ -21,68 +20,14 @@ * */ -#include "GUIControl.h" -#include "cores/IAudioCallback.h" - -#include <list> - -// forward definitions -class CVisualisation; - -#define AUDIO_BUFFER_SIZE 512 // MUST BE A POWER OF 2!!! -#define MAX_AUDIO_BUFFERS 16 +#include "GUIRenderingControl.h" -class CAudioBuffer -{ -public: - CAudioBuffer(int iSize); - virtual ~CAudioBuffer(); - const short* Get() const; - void Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample); -private: - CAudioBuffer(); - short* m_pBuffer; - int m_iLen; -}; - -class CGUIVisualisationControl : - public CGUIControl, public IAudioCallback +class CGUIVisualisationControl : public CGUIRenderingControl { public: CGUIVisualisationControl(int parentID, int controlID, float posX, float posY, float width, float height); CGUIVisualisationControl(const CGUIVisualisationControl &from); - virtual ~CGUIVisualisationControl(void); - virtual CGUIVisualisationControl *Clone() const { return new CGUIVisualisationControl(*this); }; - - virtual void Render(); - virtual void UpdateVisibility(const CGUIListItem *item = NULL); + virtual CGUIVisualisationControl *Clone() const { return new CGUIVisualisationControl(*this); }; //TODO check for naughties virtual void FreeResources(); - virtual void SetInvalid(); - virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample); - virtual void OnAudioData(const unsigned char* pAudioData, int iAudioDataLength); - virtual bool OnAction(const CAction &action); - virtual bool OnMessage(CGUIMessage& message); - virtual bool CanFocus() const; - virtual bool CanFocusFromPoint(const CPoint &point) const; - - CVisualisation *GetVisualisation(); -private: - void FreeVisualisation(); - void LoadVisualisation(); - void CreateBuffers(); - void ClearBuffers(); - bool UpdateTrack(); - CStdString m_currentVis; - CVisualisation* m_pVisualisation; - - int m_iChannels; - int m_iSamplesPerSec; - int m_iBitsPerSample; - std::list<CAudioBuffer*> m_vecBuffers; - int m_iNumBuffers; // Number of Audio buffers - bool m_bWantsFreq; - float m_fFreq[2*AUDIO_BUFFER_SIZE]; // Frequency data - bool m_bCalculate_Freq; // True if the vis wants freq data - bool m_bInitialized; - CStdString m_AlbumThumb; + virtual void Render(); }; diff --git a/guilib/Key.h b/guilib/Key.h index fd175d4b0e..b5f0113215 100644 --- a/guilib/Key.h +++ b/guilib/Key.h @@ -312,6 +312,8 @@ #define WINDOW_LOGIN_SCREEN 10029 #define WINDOW_SETTINGS_PROFILES 10034 +#define WINDOW_ADDON_BROWSER 10040 + #define WINDOW_DIALOG_YES_NO 10100 #define WINDOW_DIALOG_PROGRESS 10101 #define WINDOW_DIALOG_KEYBOARD 10103 @@ -345,7 +347,7 @@ #define WINDOW_DIALOG_SMART_PLAYLIST_RULE 10137 #define WINDOW_DIALOG_BUSY 10138 #define WINDOW_DIALOG_PICTURE_INFO 10139 -#define WINDOW_DIALOG_PLUGIN_SETTINGS 10140 +#define WINDOW_DIALOG_ADDON_SETTINGS 10140 #define WINDOW_DIALOG_ACCESS_POINTS 10141 #define WINDOW_DIALOG_FULLSCREEN_INFO 10142 #define WINDOW_DIALOG_KARAOKE_SONGSELECT 10143 diff --git a/guilib/Makefile.in b/guilib/Makefile.in index 95896d7be2..0fbe69d098 100644 --- a/guilib/Makefile.in +++ b/guilib/Makefile.in @@ -39,6 +39,7 @@ SRCS=AnimatedGif.cpp \ GUIProgressControl.cpp \ GUIRadioButtonControl.cpp \ GUIResizeControl.cpp \ + GUIRenderingControl.cpp \ GUIRSSControl.cpp \ GUIScrollBarControl.cpp \ GUISelectButtonControl.cpp \ diff --git a/language/English/strings.xml b/language/English/strings.xml index e7fb463484..a99f042e74 100644 --- a/language/English/strings.xml +++ b/language/English/strings.xml @@ -1933,6 +1933,7 @@ <string id="21416">Enable fallback based on scraper language</string> <string id="21417">- Settings</string> <string id="21418">Multilingual</string> + <string id="21419">No scrapers present</string> <string id="21420">Value to match</string> <string id="21421">Smart playlist rule</string> @@ -2087,9 +2088,6 @@ <string id="22042">white/blue</string> <string id="22043">black/white</string> - <string id="23000">Weather plugin</string> - <string id="23001">- Plugin settings</string> - <string id="23050">Activate Teletext</string> <string id="23051">Part %i</string> <string id="23052">Buffering %i bytes</string> @@ -2102,6 +2100,38 @@ <string id="23104">Click OK when playback has ended</string> + <!-- strings 24000 thru 24299 reserved for the addons framework --> + <string id="24000">Add-on</string> + <string id="24001">Add-ons</string> + + <string id="24005">Plugin</string> + <string id="24007">Scraper</string> + <string id="24008">Screensaver</string> + <string id="24009">Script</string> + <string id="24010">Visualization</string> + + <string id="24020">Configure Add-on</string> + <string id="24021">Disable Add-on</string> + <string id="24022">Enable Add-on</string> + <string id="24030">This Add-on can not be configured</string> + <string id="24031">Error loading settings</string> + + <string id="24050">Available Add-ons</string> + <string id="24051">Version:</string> + <string id="24052">Disclaimer:</string> + <string id="24053">License:</string> + <string id="24059">Would you like to install this Add-on?</string> + + <string id="24070">Add-on can not used</string> + <string id="24071">An unknown error has occurred</string> + <string id="24072">Settings required</string> + <string id="24073">Could not connect</string> + <string id="24074">Needs to restart</string> + <string id="24080">Try to reconnect?</string> + <string id="24089">Add-on restarts</string> + + <string id="24090">Lock Add-on manager</string> + <!-- strings 29800 thru 29998 reserved strings used only in the default Project Mayhem III skin and not c++ code --> <string id="29800">Library Mode</string> <string id="29801">QWERTY keyboard</string> diff --git a/project/VS2008Express/XBMC.vcproj b/project/VS2008Express/XBMC.vcproj index d9cc53b9d5..bfabccf447 100644 --- a/project/VS2008Express/XBMC.vcproj +++ b/project/VS2008Express/XBMC.vcproj @@ -467,6 +467,10 @@ > </File> <File + RelativePath="..\..\xbmc\win32\strverscmp.cpp" + > + </File> + <File RelativePath="..\..\xbmc\win32\Win32DelayedDllLoad.cpp" > </File> @@ -2097,14 +2101,6 @@ RelativePath="..\..\xbmc\visualizations\Visualisation.h" > </File> - <File - RelativePath="..\..\xbmc\visualizations\VisualisationFactory.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\visualizations\VisualisationFactory.h" - > - </File> </Filter> <Filter Name="VideoRenderers" @@ -2230,14 +2226,6 @@ > </File> <File - RelativePath="..\..\xbmc\screensavers\ScreenSaverFactory.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\screensavers\ScreenSaverFactory.h" - > - </File> - <File RelativePath="..\..\xbmc\screensavers\xbmc_scr.h" > </File> @@ -2358,14 +2346,6 @@ > </File> <File - RelativePath="..\..\xbmc\GUIDialogPluginSettings.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\GUIDialogPluginSettings.h" - > - </File> - <File RelativePath="..\..\xbmc\GUISettings.cpp" > </File> @@ -2410,27 +2390,11 @@ > </File> <File - RelativePath="..\..\xbmc\PluginSettings.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\PluginSettings.h" - > - </File> - <File - RelativePath="..\..\xbmc\ScraperSettings.cpp" + RelativePath="..\..\xbmc\Scraper.cpp" > </File> <File - RelativePath="..\..\xbmc\ScraperSettings.h" - > - </File> - <File - RelativePath="..\..\xbmc\ScriptSettings.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\ScriptSettings.h" + RelativePath="..\..\xbmc\Scraper.h" > </File> <File @@ -2882,6 +2846,26 @@ Name="Utils" > <File + RelativePath="..\..\xbmc\utils\Addon.cpp" + > + </File> + <File + RelativePath="..\..\xbmc\utils\Addon.h" + > + </File> + <File + RelativePath="..\..\xbmc\utils\AddonDll.h" + > + </File> + <File + RelativePath="..\..\xbmc\utils\AddonManager.cpp" + > + </File> + <File + RelativePath="..\..\xbmc\utils\AddonManager.h" + > + </File> + <File RelativePath="..\..\xbmc\utils\AlarmClock.cpp" > </File> @@ -3562,6 +3546,14 @@ > </File> <File + RelativePath="..\..\xbmc\GUIDialogAddonSettings.cpp" + > + </File> + <File + RelativePath="..\..\xbmc\GUIDialogAddonSettings.h" + > + </File> + <File RelativePath="..\..\xbmc\GUIDialogAudioSubtitleSettings.cpp" > </File> @@ -3786,14 +3778,6 @@ > </File> <File - RelativePath="..\..\xbmc\GUIDialogVisualisationSettings.cpp" - > - </File> - <File - RelativePath="..\..\xbmc\GUIDialogVisualisationSettings.h" - > - </File> - <File RelativePath="..\..\xbmc\GUIDialogVolumeBar.cpp" > </File> @@ -3846,6 +3830,14 @@ > </File> <File + RelativePath="..\..\xbmc\GUIWindowAddonBrowser.cpp" + > + </File> + <File + RelativePath="..\..\xbmc\GUIWindowAddonBrowser.h" + > + </File> + <File RelativePath="..\..\xbmc\GUIWindowFileManager.cpp" > </File> @@ -3966,6 +3958,14 @@ Name="Filesystem" > <File + RelativePath="..\..\xbmc\FileSystem\AddonsDirectory.cpp" + > + </File> + <File + RelativePath="..\..\xbmc\FileSystem\AddonsDirectory.h" + > + </File> + <File RelativePath="..\..\xbmc\FileSystem\ASAPFileDirectory.cpp" > </File> diff --git a/project/VS2008Express/guilib.vcproj b/project/VS2008Express/guilib.vcproj index 0623d79646..f98320b4d6 100644 --- a/project/VS2008Express/guilib.vcproj +++ b/project/VS2008Express/guilib.vcproj @@ -486,6 +486,14 @@ >
</File>
<File
+ RelativePath="..\..\guilib\GUIRenderingControl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\guilib\GUIRenderingControl.h"
+ >
+ </File>
+ <File
RelativePath="..\..\guilib\GUIResizeControl.cpp"
>
</File>
diff --git a/skin/Confluence/720p/AddonBrowser.xml b/skin/Confluence/720p/AddonBrowser.xml new file mode 100644 index 0000000000..8f9ec8b984 --- /dev/null +++ b/skin/Confluence/720p/AddonBrowser.xml @@ -0,0 +1,313 @@ +<window id="40"> + <defaultcontrol always="true">2</defaultcontrol> + <allowoverlay>no</allowoverlay> + <controls> + <include>CommonSettingsBackground</include> + <include>CommonMediaPlayingBackground</include> + <control type="group"> + <posx>90</posx> + <posy>50</posy> + <animation type="WindowOpen" reversible="false"> + <effect type="zoom" start="80" end="100" center="640,360" easing="out" tween="back" time="300" /> + <effect type="fade" start="0" end="100" time="300" /> + </animation> + <animation type="WindowClose" reversible="false"> + <effect type="zoom" start="100" end="80" center="640,360" easing="in" tween="back" time="300" /> + <effect type="fade" start="100" end="0" time="300" /> + </animation> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>1100</width> + <height>640</height> + <texture border="20">DialogBack.png</texture> + </control> + <control type="image"> + <description>LOGO</description> + <posx>30</posx> + <posy>15</posy> + <width>220</width> + <height>80</height> + <aspectratio>keep</aspectratio> + <texture>Confluence_Logo.png</texture> + </control> + <control type="image"> + <posx>268</posx> + <posy>10</posy> + <width>790</width> + <height>618</height> + <texture border="5">black-back2.png</texture> + </control> + <control type="image"> + <posx>268</posx> + <posy>10</posy> + <width>804</width> + <height>70</height> + <aspectratio>stretch</aspectratio> + <texture>GlassTitleBar.png</texture> + </control> + <control type="label"> + <description>header label</description> + <posx>300</posx> + <posy>20</posy> + <width>740</width> + <height>30</height> + <font>font16caps</font> + <label>$LOCALIZE[24001]</label> + <align>left</align> + <aligny>center</aligny> + <textcolor>white</textcolor> + <shadowcolor>black</shadowcolor> + </control> + <control type="list" id="2"> + <posx>283</posx> + <posy>70</posy> + <width>750</width> + <height>540</height> + <onup>2</onup> + <ondown>2</ondown> + <onleft>53</onleft> + <onright>60</onright> + <pagecontrol>60</pagecontrol> + <scrolltime>200</scrolltime> + <itemlayout height="75" width="750"> + <control type="group"> + <visible>![$INFO[ListItem.Property(Addon.Disabled)]]</visible> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <aspectratio>stretch</aspectratio> + <texture border="5">button-nofocus.png</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>$INFO[ListItem.Icon]</texture> + </control> + <control type="label"> + <posx>110</posx> + <posy>2</posy> + <width>450</width> + <height>28</height> + <font>font13</font> + <textcolor>grey2</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>[B]$INFO[ListItem.Property(Addon.Name)][/B] - $INFO[ListItem.Property(Addon.Version)]</label> + </control> + <control type="label"> + <posx>110</posx> + <posy>25</posy> + <width>450</width> + <height>25</height> + <font>font12</font> + <textcolor>grey2</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Property(Addon.Summary)]</label> + </control> + </control> + <control type="group"> + <visible>$INFO[ListItem.Property(Addon.Disabled)]</visible> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <aspectratio>stretch</aspectratio> + <texture border="5">button-nofocus.png</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>$INFO[ListItem.Icon]</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>Fanart-Diffuse.png</texture> + </control> + <control type="label"> + <posx>110</posx> + <posy>2</posy> + <width>450</width> + <height>28</height> + <font>font13</font> + <textcolor>grey3</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>[B]$INFO[ListItem.Property(Addon.Name)][/B] - $INFO[ListItem.Property(Addon.Version)]</label> + </control> + <control type="label"> + <posx>110</posx> + <posy>25</posy> + <width>450</width> + <height>25</height> + <font>font12</font> + <textcolor>grey3</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Property(Addon.Summary)]</label> + </control> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <texture>black-back2.png</texture> + </control> + </control> + </itemlayout> + <focusedlayout height="75" width="750"> + <control type="group"> + <visible>![$INFO[ListItem.Property(Addon.Disabled)]]</visible> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <aspectratio>stretch</aspectratio> + <texture border="5">button-focus.png</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>$INFO[ListItem.Icon]</texture> + </control> + <control type="label"> + <posx>110</posx> + <posy>2</posy> + <width>450</width> + <height>28</height> + <font>font13</font> + <textcolor>white</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>[B]$INFO[ListItem.Property(Addon.Name)][/B] - $INFO[ListItem.Property(Addon.Version)]</label> + </control> + <control type="label"> + <posx>110</posx> + <posy>25</posy> + <width>450</width> + <height>25</height> + <font>font12</font> + <textcolor>white</textcolor> + <selectedcolor>selected</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Property(Addon.Summary)]</label> + </control> + </control> + <control type="group"> + <visible>$INFO[ListItem.Property(Addon.Disabled)]</visible> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <aspectratio>stretch</aspectratio> + <texture border="5">button-focus.png</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>$INFO[ListItem.Icon]</texture> + </control> + <control type="image"> + <posx>10</posx> + <posy>2</posy> + <width>90</width> + <height>66</height> + <texture>Fanart-Diffuse.png</texture> + </control> + <control type="label"> + <posx>110</posx> + <posy>2</posy> + <width>450</width> + <height>28</height> + <font>font13</font> + <textcolor>grey3</textcolor> + <selectedcolor>grey3</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>[B]$INFO[ListItem.Property(Addon.Name)][/B] - $INFO[ListItem.Property(Addon.Version)]</label> + </control> + <control type="label"> + <posx>110</posx> + <posy>25</posy> + <width>450</width> + <height>25</height> + <font>font12</font> + <textcolor>grey3</textcolor> + <selectedcolor>grey3</selectedcolor> + <align>left</align> + <aligny>center</aligny> + <label>$INFO[ListItem.Property(Addon.Summary)]</label> + </control> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>750</width> + <height>75</height> + <texture>black-back2.png</texture> + <visible>$INFO[ListItem.Property(Addon.Disabled)]</visible> + </control> + </control> + </focusedlayout> + </control> + <control type="scrollbar" id="60"> + <posx>1060</posx> + <posy>60</posy> + <width>25</width> + <height>530</height> + <texturesliderbackground border="0,14,0,14">ScrollBarV.png</texturesliderbackground> + <texturesliderbar border="0,14,0,14">ScrollBarV_bar.png</texturesliderbar> + <texturesliderbarfocus border="0,14,0,14">ScrollBarV_bar_focus.png</texturesliderbarfocus> + <textureslidernib>ScrollBarNib.png</textureslidernib> + <textureslidernibfocus>ScrollBarNib.png</textureslidernibfocus> + <onleft>2</onleft> + <onright>4</onright> + <showonepage>false</showonepage> + <orientation>vertical</orientation> + </control> + </control> + <include>BehindDialogFadeOut</include> + <control type="group"> + <posx>60</posx> + <posy>0</posy> + <animation effect="slide" end="-310,0" time="400" tween="quadratic" easing="out" condition="Window.Next(Home) | Window.Next(1111)">WindowClose</animation> + <animation effect="slide" start="-310,0" time="400" tween="quadratic" easing="out" condition="Window.Previous(Home) | Window.Previous(1111)">WindowOpen</animation> + <control type="image"> + <posx>0</posx> + <posy>0</posy> + <width>250</width> + <height>35</height> + <texture border="0,0,32,0">header.png</texture> + </control> + <control type="label"> + <include>WindowTitleCommons</include> + <posx>220</posx> + <label>$LOCALIZE[5]</label> + </control> + </control> + <include>WindowTitleHomeButton</include> + <include>Clock</include> + </controls> +</window> diff --git a/skin/Confluence/720p/DialogAddonSettings.xml b/skin/Confluence/720p/DialogAddonSettings.xml new file mode 100644 index 0000000000..d3c1593a94 --- /dev/null +++ b/skin/Confluence/720p/DialogAddonSettings.xml @@ -0,0 +1,166 @@ +<window id="10140">
+ <defaultcontrol always="true">2</defaultcontrol>
+ <coordinates>
+ <system>1</system>
+ <posx>240</posx>
+ <posy>55</posy>
+ </coordinates>
+ <include>dialogeffect</include>
+ <controls>
+ <control type="image">
+ <description>background image</description>
+ <posx>0</posx>
+ <posy>0</posy>
+ <width>800</width>
+ <height>610</height>
+ <texture border="40">DialogBack.png</texture>
+ </control>
+ <control type="image">
+ <posx>80</posx>
+ <posy>10</posy>
+ <width>640</width>
+ <height>90</height>
+ <aspectratio>stretch</aspectratio>
+ <texture>GlassTitleBar.png</texture>
+ </control>
+ <control type="button">
+ <description>Close Window button</description>
+ <posx>710</posx>
+ <posy>9</posy>
+ <width>64</width>
+ <height>32</height>
+ <label>-</label>
+ <font>-</font>
+ <onclick>PreviousMenu</onclick>
+ <texturefocus>DialogCloseButton-focus.png</texturefocus>
+ <texturenofocus>DialogCloseButton.png</texturenofocus>
+ <onleft>2</onleft>
+ <onright>2</onright>
+ <onup>2</onup>
+ <ondown>2</ondown>
+ <visible>system.getbool(input.enablemouse)</visible>
+ </control>
+ <control type="label" id="20">
+ <description>header label</description>
+ <posx>20</posx>
+ <posy>18</posy>
+ <width>760</width>
+ <height>30</height>
+ <font>font13_title</font>
+ <label>-</label>
+ <align>center</align>
+ <aligny>center</aligny>
+ <textcolor>white</textcolor>
+ <shadowcolor>black</shadowcolor>
+ </control>
+ <control type="grouplist" id="2">
+ <description>control area</description>
+ <posx>30</posx>
+ <posy>80</posy>
+ <width>740</width>
+ <height>420</height>
+ <itemgap>-1</itemgap>
+ <onup>2</onup>
+ <ondown>2</ondown>
+ <onleft>10</onleft>
+ <onright>10</onright>
+ </control>
+ <control type="button" id="3">
+ <description>Default Button</description>
+ <height>40</height>
+ <font>font13</font>
+ <textcolor>grey2</textcolor>
+ <focusedcolor>white</focusedcolor>
+ <texturefocus border="0,2,0,2">MenuItemFO.png</texturefocus>
+ <texturenofocus border="0,2,0,2">MenuItemNF.png</texturenofocus>
+ </control>
+ <control type="radiobutton" id="4">
+ <description>Default RadioButton</description>
+ <height>40</height>
+ <font>font13</font>
+ <textcolor>grey2</textcolor>
+ <focusedcolor>white</focusedcolor>
+ <texturefocus border="0,2,0,2">MenuItemFO.png</texturefocus>
+ <texturenofocus border="0,2,0,2">MenuItemNF.png</texturenofocus>
+ </control>
+ <control type="spincontrolex" id="5">
+ <description>Default spincontrolex</description>
+ <height>40</height>
+ <textcolor>grey2</textcolor>
+ <focusedcolor>white</focusedcolor>
+ <texturefocus border="0,2,0,2">MenuItemFO.png</texturefocus>
+ <texturenofocus border="0,2,0,2">MenuItemNF.png</texturenofocus>
+ <font>font13</font>
+ <aligny>center</aligny>
+ <reverse>yes</reverse>
+ </control>
+ <control type="label" id="7">
+ <height>45</height>
+ <font>font13_title</font>
+ <label>-</label>
+ <textcolor>blue</textcolor>
+ <shadowcolor>black</shadowcolor>
+ <align>left</align>
+ <aligny>center</aligny>
+ </control>
+ <control type="image" id="6">
+ <description>Default Seperator</description>
+ <height>2</height>
+ <texture>separator2.png</texture>
+ </control>
+ <control type="group" id="9001">
+ <posy>540</posy>
+ <control type="button" id="10">
+ <description>OK Button</description>
+ <posx>300</posx>
+ <posy>0</posy>
+ <width>200</width>
+ <height>40</height>
+ <align>center</align>
+ <aligny>center</aligny>
+ <texturenofocus border="5">MenuItemNF.png</texturenofocus>
+ <texturefocus border="5">button-focus.png</texturefocus>
+ <font>font12_title</font>
+ <label>186</label>
+ <onleft>12</onleft>
+ <onright>11</onright>
+ <onup>2</onup>
+ <ondown>2</ondown>
+ </control>
+ <control type="button" id="11">
+ <description>Cancel Button</description>
+ <posx>510</posx>
+ <posy>0</posy>
+ <width>200</width>
+ <height>40</height>
+ <align>center</align>
+ <aligny>center</aligny>
+ <texturenofocus border="5">MenuItemNF.png</texturenofocus>
+ <texturefocus border="5">button-focus.png</texturefocus>
+ <font>font12_title</font>
+ <label>222</label>
+ <onleft>10</onleft>
+ <onright>12</onright>
+ <onup>2</onup>
+ <ondown>2</ondown>
+ </control>
+ <control type="button" id="12">
+ <description>Defaults Button</description>
+ <posx>90</posx>
+ <posy>0</posy>
+ <width>200</width>
+ <height>40</height>
+ <align>center</align>
+ <aligny>center</aligny>
+ <texturenofocus border="5">MenuItemNF.png</texturenofocus>
+ <texturefocus border="5">button-focus.png</texturefocus>
+ <font>font12_title</font>
+ <label>409</label>
+ <onleft>11</onleft>
+ <onright>10</onright>
+ <onup>2</onup>
+ <ondown>2</ondown>
+ </control>
+ </control>
+ </controls>
+</window>
diff --git a/skin/Confluence/720p/Settings.xml b/skin/Confluence/720p/Settings.xml index 58d9d135d8..6aa3ea6a91 100644 --- a/skin/Confluence/720p/Settings.xml +++ b/skin/Confluence/720p/Settings.xml @@ -35,7 +35,7 @@ <posx>10</posx>
<posy>90</posy>
<width>260</width>
- <height>481</height>
+ <height>541</height>
<onleft>9000</onleft>
<onright>9001</onright>
<onup>9000</onup>
@@ -114,18 +114,24 @@ <icon>special://skin/backgrounds/weather.jpg</icon>
</item>
<item id="6">
+ <label>24001</label>
+ <label2>31408</label2>
+ <onclick>ActivateWindow(AddonBrowser)</onclick>
+ <icon>special://skin/backgrounds/addons.jpg</icon>
+ </item>
+ <item id="7">
<label>705</label>
<label2>31405</label2>
<onclick>ActivateWindow(NetworkSettings)</onclick>
<icon>special://skin/backgrounds/network.jpg</icon>
</item>
- <item id="7">
+ <item id="8">
<label>13000</label>
<label2>31406</label2>
<onclick>ActivateWindow(SystemSettings)</onclick>
<icon>special://skin/backgrounds/system.jpg</icon>
</item>
- <item id="8">
+ <item id="9">
<label>166</label>
<label2>31407</label2>
<onclick>ActivateWindow(1111)</onclick>
diff --git a/skin/Confluence/720p/VisualisationPresetList.xml b/skin/Confluence/720p/VisualisationPresetList.xml index 64d3d5f7b1..cace47e7d0 100644 --- a/skin/Confluence/720p/VisualisationPresetList.xml +++ b/skin/Confluence/720p/VisualisationPresetList.xml @@ -61,7 +61,7 @@ <posy>180</posy>
<width>760</width>
<align>center</align>
- <label>13390</label>
+ <label>13389</label>
<font>font13caps</font>
</control>
<control type="list" id="2">
@@ -148,4 +148,4 @@ </control>
</control>
</controls>
-</window>
\ No newline at end of file +</window>
diff --git a/skin/Confluence/720p/custom_SkinSetting_1111.xml b/skin/Confluence/720p/custom_SkinSetting_1111.xml index 0ca9845bcf..ce045ebc91 100644 --- a/skin/Confluence/720p/custom_SkinSetting_1111.xml +++ b/skin/Confluence/720p/custom_SkinSetting_1111.xml @@ -1363,7 +1363,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton1_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton1_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton1)</visible>
</control>
@@ -1402,7 +1402,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton2_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton2_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton2)</visible>
</control>
@@ -1441,7 +1441,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton3_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton3_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton3)</visible>
</control>
@@ -1480,7 +1480,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton4_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton4_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton4)</visible>
</control>
@@ -1519,7 +1519,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton5_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton5_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton5)</visible>
</control>
@@ -1558,7 +1558,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(HomeScriptButton6_Path,.py)</onclick>
+ <onclick>Skin.SetFile(HomeScriptButton6_Path,Script)</onclick>
<visible>Skin.HasSetting(HomeScriptButton6)</visible>
</control>
@@ -1608,7 +1608,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(WeatherScript_Path,.py)</onclick>
+ <onclick>Skin.SetFile(WeatherScript_Path,Plugin,Weather)</onclick>
<visible>Skin.HasSetting(WeatherScript_Enable)</visible>
</control>
@@ -1645,7 +1645,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(LyricScript_Path,.py)</onclick>
+ <onclick>Skin.SetFile(LyricScript_Path,Script)</onclick>
<visible>Skin.HasSetting(LyricScript_Enable)</visible>
</control>
@@ -1682,7 +1682,7 @@ <focusedcolor>white</focusedcolor>
<texturefocus>MenuItemFO.png</texturefocus>
<texturenofocus>MenuItemNF.png</texturenofocus>
- <onclick>Skin.SetFile(SubtitleScript_Path,.py)</onclick>
+ <onclick>Skin.SetFile(SubtitleScript_Path,Script)</onclick>
<visible>Skin.HasSetting(SubtitleDownload_Enable)</visible>
</control>
</control>
diff --git a/skin/Confluence/language/English/strings.xml b/skin/Confluence/language/English/strings.xml index a3e9c330fb..25745c749a 100644 --- a/skin/Confluence/language/English/strings.xml +++ b/skin/Confluence/language/English/strings.xml @@ -149,6 +149,7 @@ <string id="31405">[B]CONFIGURE NETWORK SETTINGS[/B][CR][CR]Setup control of XBMC via UPnP and HTTP · Configure file sharing[CR]Set internet access options</string>
<string id="31406">[B]CONFIGURE SYSTEM SETTINGS[/B][CR][CR]Setup and calibrate displays · Configure audio output · Setup remote controls[CR]Set power saving options · Enable debugging · Setup master lock</string>
<string id="31407">[B]CONFIGURE SKIN SETTINGS[/B][CR][CR]Setup the Confluence skin · Add and remove home menu items[CR]Change skin backgrounds</string> + <string id="31408">[B]CONFIGURE ADD-ONS[/B][CR][CR]Manage your installed Add-ons · Browse for and install Add-ons from xbmc.org[CR]Modify Add-on settings</string> <string id="31421">Select your XBMC user Profile[CR]to login and continue</string>
</strings>
diff --git a/skin/PM3.HD/720p/DialogPluginSettings.xml b/skin/PM3.HD/720p/DialogAddonSettings.xml index ed57e8ade4..1c2c42b8cc 100644 --- a/skin/PM3.HD/720p/DialogPluginSettings.xml +++ b/skin/PM3.HD/720p/DialogAddonSettings.xml @@ -1,145 +1,145 @@ -<window id="10140">
- <defaultcontrol>2</defaultcontrol>
- <coordinates>
- <system>1</system>
- <posx>240</posx>
- <posy>55</posy>
- </coordinates>
- <include>dialogeffect</include>
- <controls>
- <control type="image">
- <description>background image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>800</width>
- <height>610</height>
- <texture border="40">DialogBack.png</texture>
- </control>
- <control type="image">
- <description>background image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>800</width>
- <height>610</height>
- <texture border="40">DialogFront.png</texture>
- </control>
- <control type="label" id="20">
- <description>heading label</description>
- <posx>40</posx>
- <posy>40</posy>
- <width>720</width>
- <height>30</height>
- <align>center</align>
- <aligny>center</aligny>
- <font>font18</font>
- <label>-</label>
- <textcolor>dialogheader</textcolor>
- </control>
- <control type="image">
- <posx>40</posx>
- <posy>78</posy>
- <width>720</width>
- <height>2</height>
- <texture>separator.png</texture>
- </control>
- <control type="grouplist" id="2">
- <description>control area</description>
- <posx>40</posx>
- <posy>85</posy>
- <width>720</width>
- <height>420</height>
- <itemgap>5</itemgap>
- <onup>2</onup>
- <ondown>2</ondown>
- <onleft>10</onleft>
- <onright>10</onright>
- </control>
- <control type="button" id="3">
- <description>Default Button</description>
- <height>35</height>
- <font>font12</font>
- <texturefocus border="3">button-focus.png</texturefocus>
- <texturenofocus border="3">button-nofocus.png</texturenofocus>
- </control>
- <control type="radiobutton" id="4">
- <description>Default RadioButton</description>
- <height>35</height>
- <font>font12</font>
- <texturefocus border="3">button-focus.png</texturefocus>
- <texturenofocus border="3">button-nofocus.png</texturenofocus>
- </control>
- <control type="spincontrolex" id="5">
- <description>Default spincontrolex</description>
- <height>35</height>
- <texturefocus border="3">button-focus.png</texturefocus>
- <texturenofocus border="3">button-nofocus.png</texturenofocus>
- <font>font12</font>
- <aligny>center</aligny>
- <reverse>yes</reverse>
- </control>
- <control type="image" id="6">
- <description>Default Seperator</description>
- <height>2</height>
- <texture>separator.png</texture>
- </control>
- <control type="label" id="7">
- <description>Separator label</description>
- <label></label>
- <height>25</height>
- <font>font12</font>
- <align>center</align>
- <aligny>bottom</aligny>
- <textcolor>green</textcolor>
- </control>
- <control type="group" id="9001">
- <control type="button" id="10">
- <description>OK Button</description>
- <posx>300</posx>
- <posy>525</posy>
- <width>200</width>
- <height>35</height>
- <align>center</align>
- <aligny>center</aligny>
- <texturenofocus>button-nofocus.png</texturenofocus>
- <texturefocus>button-focus2.png</texturefocus>
- <label>186</label>
- <onleft>12</onleft>
- <onright>11</onright>
- <onup>2</onup>
- <ondown>2</ondown>
- </control>
- <control type="button" id="11">
- <description>Cancel Button</description>
- <posx>510</posx>
- <posy>525</posy>
- <width>200</width>
- <height>35</height>
- <align>center</align>
- <aligny>center</aligny>
- <texturenofocus>button-nofocus.png</texturenofocus>
- <texturefocus>button-focus2.png</texturefocus>
- <label>222</label>
- <onleft>10</onleft>
- <onright>12</onright>
- <onup>2</onup>
- <ondown>2</ondown>
- </control>
- <control type="button" id="12">
- <description>Defaults Button</description>
- <posx>90</posx>
- <posy>525</posy>
- <width>200</width>
- <height>35</height>
- <align>center</align>
- <aligny>center</aligny>
- <texturenofocus>button-nofocus.png</texturenofocus>
- <texturefocus>button-focus2.png</texturefocus>
- <label>409</label>
- <onleft>11</onleft>
- <onright>10</onright>
- <onup>2</onup>
- <ondown>2</ondown>
- </control>
- </control>
- </controls>
-</window>
+<window id="10140"> + <defaultcontrol>2</defaultcontrol> + <coordinates> + <system>1</system> + <posx>240</posx> + <posy>55</posy> + </coordinates> + <include>dialogeffect</include> + <controls> + <control type="image"> + <description>background image</description> + <posx>0</posx> + <posy>0</posy> + <width>800</width> + <height>610</height> + <texture border="40">DialogBack.png</texture> + </control> + <control type="image"> + <description>background image</description> + <posx>0</posx> + <posy>0</posy> + <width>800</width> + <height>610</height> + <texture border="40">DialogFront.png</texture> + </control> + <control type="label" id="20"> + <description>heading label</description> + <posx>40</posx> + <posy>40</posy> + <width>720</width> + <height>30</height> + <align>center</align> + <aligny>center</aligny> + <font>font18</font> + <label>-</label> + <textcolor>dialogheader</textcolor> + </control> + <control type="image"> + <posx>40</posx> + <posy>78</posy> + <width>720</width> + <height>2</height> + <texture>separator.png</texture> + </control> + <control type="grouplist" id="2"> + <description>control area</description> + <posx>40</posx> + <posy>85</posy> + <width>720</width> + <height>420</height> + <itemgap>5</itemgap> + <onup>2</onup> + <ondown>2</ondown> + <onleft>10</onleft> + <onright>10</onright> + </control> + <control type="button" id="3"> + <description>Default Button</description> + <height>35</height> + <font>font12</font> + <texturefocus border="3">button-focus.png</texturefocus> + <texturenofocus border="3">button-nofocus.png</texturenofocus> + </control> + <control type="radiobutton" id="4"> + <description>Default RadioButton</description> + <height>35</height> + <font>font12</font> + <texturefocus border="3">button-focus.png</texturefocus> + <texturenofocus border="3">button-nofocus.png</texturenofocus> + </control> + <control type="spincontrolex" id="5"> + <description>Default spincontrolex</description> + <height>35</height> + <texturefocus border="3">button-focus.png</texturefocus> + <texturenofocus border="3">button-nofocus.png</texturenofocus> + <font>font12</font> + <aligny>center</aligny> + <reverse>yes</reverse> + </control> + <control type="image" id="6"> + <description>Default Seperator</description> + <height>2</height> + <texture>separator.png</texture> + </control> + <control type="label" id="7"> + <description>Separator label</description> + <label></label> + <height>25</height> + <font>font12</font> + <align>center</align> + <aligny>bottom</aligny> + <textcolor>green</textcolor> + </control> + <control type="group" id="9001"> + <control type="button" id="10"> + <description>OK Button</description> + <posx>300</posx> + <posy>525</posy> + <width>200</width> + <height>35</height> + <align>center</align> + <aligny>center</aligny> + <texturenofocus>button-nofocus.png</texturenofocus> + <texturefocus>button-focus2.png</texturefocus> + <label>186</label> + <onleft>12</onleft> + <onright>11</onright> + <onup>2</onup> + <ondown>2</ondown> + </control> + <control type="button" id="11"> + <description>Cancel Button</description> + <posx>510</posx> + <posy>525</posy> + <width>200</width> + <height>35</height> + <align>center</align> + <aligny>center</aligny> + <texturenofocus>button-nofocus.png</texturenofocus> + <texturefocus>button-focus2.png</texturefocus> + <label>222</label> + <onleft>10</onleft> + <onright>12</onright> + <onup>2</onup> + <ondown>2</ondown> + </control> + <control type="button" id="12"> + <description>Defaults Button</description> + <posx>90</posx> + <posy>525</posy> + <width>200</width> + <height>35</height> + <align>center</align> + <aligny>center</aligny> + <texturenofocus>button-nofocus.png</texturenofocus> + <texturefocus>button-focus2.png</texturefocus> + <label>409</label> + <onleft>11</onleft> + <onright>10</onright> + <onup>2</onup> + <ondown>2</ondown> + </control> + </control> + </controls> +</window> diff --git a/skin/PM3.HD/720p/DialogContentSettings.xml b/skin/PM3.HD/720p/DialogContentSettings.xml index 6ab32f87f7..9f1ec1f8ba 100644 --- a/skin/PM3.HD/720p/DialogContentSettings.xml +++ b/skin/PM3.HD/720p/DialogContentSettings.xml @@ -67,6 +67,7 @@ <height>200</height>
<aspectratio>keep</aspectratio>
<info>ListItem.Icon</info>
+ <visible>Control.IsVisible(4)</visible>
</control>
<control type="list" id="4">
<posx>40</posx>
diff --git a/skin/PM3.HD/720p/MusicOSDVisSettings.xml b/skin/PM3.HD/720p/MusicOSDVisSettings.xml deleted file mode 100644 index ac4fd7056f..0000000000 --- a/skin/PM3.HD/720p/MusicOSDVisSettings.xml +++ /dev/null @@ -1,105 +0,0 @@ -<window id="121">
- <defaultcontrol>2</defaultcontrol>
- <coordinates>
- <system>1</system>
- <posx>400</posx>
- <posy>55</posy>
- </coordinates>
- <include>dialogeffect</include>
- <controls>
- <control type="image">
- <description>background image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>800</width>
- <height>610</height>
- <colordiffuse>DDFFFFFF</colordiffuse>
- <texture border="40">DialogBack.png</texture>
- </control>
- <control type="image">
- <description>background image</description>
- <posx>0</posx>
- <posy>0</posy>
- <width>800</width>
- <height>610</height>
- <texture border="40">DialogFront.png</texture>
- </control>
- <control type="button">
- <description>Close Window button</description>
- <posx>731</posx>
- <posy>35</posy>
- <width>35</width>
- <height>25</height>
- <label>-</label>
- <font>-</font>
- <onclick>Dialog.Close(121)</onclick>
- <texturefocus>close-windowFO.png</texturefocus>
- <texturenofocus>close-window.png</texturenofocus>
- <onleft>5</onleft>
- <onright>5</onright>
- <onup>5</onup>
- <ondown>5</ondown>
- <visible>system.getbool(input.enablemouse)</visible>
- </control>
- <control type="label" id="2">
- <description>heading label</description>
- <posx>40</posx>
- <posy>40</posy>
- <width>720</width>
- <height>30</height>
- <align>center</align>
- <aligny>center</aligny>
- <font>font18</font>
- <label>-</label>
- <textcolor>dialogheader</textcolor>
- </control>
- <control type="image">
- <posx>40</posx>
- <posy>78</posy>
- <width>720</width>
- <height>2</height>
- <texture>separator.png</texture>
- </control>
- <control type="grouplist" id="5">
- <description>control area</description>
- <posx>45</posx>
- <posy>85</posy>
- <width>710</width>
- <height>480</height>
- <itemgap>5</itemgap>
- <pagecontrol>60</pagecontrol>
- <onleft>5</onleft>
- <onright>5</onright>
- <onup>5</onup>
- <ondown>5</ondown>
- </control>
- <control type="button" id="7">
- <description>Default Button</description>
- <height>35</height>
- <font>font12</font>
- <textcolor>grey2</textcolor>
- <focusedcolor>white</focusedcolor>
- <texturefocus border="5">button-focus.png</texturefocus>
- <texturenofocus border="5">button-nofocus.png</texturenofocus>
- </control>
- <control type="radiobutton" id="8">
- <description>Default RadioButton</description>
- <height>35</height>
- <font>font12</font>
- <textcolor>grey2</textcolor>
- <focusedcolor>white</focusedcolor>
- <texturefocus border="5">button-focus.png</texturefocus>
- <texturenofocus border="5">button-nofocus.png</texturenofocus>
- </control>
- <control type="spincontrolex" id="9">
- <description>Default spincontrolex</description>
- <height>35</height>
- <texturefocus border="5">button-focus.png</texturefocus>
- <texturenofocus border="5">button-nofocus.png</texturenofocus>
- <font>font12</font>
- <textcolor>grey2</textcolor>
- <focusedcolor>white</focusedcolor>
- <reverse>yes</reverse>
- </control>
- </controls>
-</window>
\ No newline at end of file diff --git a/system/keymaps/keyboard.xml b/system/keymaps/keyboard.xml index 67888bd658..ac0bbd0c2e 100644 --- a/system/keymaps/keyboard.xml +++ b/system/keymaps/keyboard.xml @@ -412,6 +412,11 @@ <backspace>PreviousMenu</backspace> </keyboard> </Settings> + <AddonBrowser> + <keyboard> + <backspace>PreviousMenu</backspace> + </keyboard> + </AddonBrowser> <MyPicturesSettings> <keyboard> <backspace>PreviousMenu</backspace> diff --git a/system/keymaps/remote.xml b/system/keymaps/remote.xml index 07275cbc55..d9ebed1b6e 100644 --- a/system/keymaps/remote.xml +++ b/system/keymaps/remote.xml @@ -363,6 +363,11 @@ <back>PreviousMenu</back> </remote> </Settings> + <AddonBrowser> + <remote> + <back>PreviousMenu</back> + </remote> + </AddonBrowser> <MyPicturesSettings> <remote> <back>PreviousMenu</back> diff --git a/visualisations/xbmc_vis.h b/visualisations/xbmc_vis.h deleted file mode 100644 index ecb19c38ca..0000000000 --- a/visualisations/xbmc_vis.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __XBMC_VIS_H__ -#define __XBMC_VIS_H__ - -#include <vector> -#include <ctype.h> -#ifdef _LINUX -#include "../xbmc/linux/PlatformInclude.h" -#ifndef __APPLE__ -#include <sys/sysinfo.h> -#endif -#else -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include <windows.h> -#endif -#include "../xbmc/utils/log.h" -#include "../xbmc/visualizations/VisualisationTypes.h" -#include <sys/stat.h> -#include <errno.h> - -using namespace std; - -int htoi(const char *str) /* Convert hex string to integer */ -{ - unsigned int digit, number = 0; - while (*str) - { - if (isdigit(*str)) - digit = *str - '0'; - else - digit = tolower(*str)-'a'+10; - number<<=4; - number+=digit; - str++; - } - return number; -} - -// the settings vector -vector<VisSetting> m_vecSettings; - - -extern "C" -{ - // exports for d3d hacks -#ifdef HAS_DX - void d3dSetTextureStageState( int x, DWORD dwY, DWORD dwZ); - void d3dSetRenderState(DWORD dwY, DWORD dwZ); -#endif - -#ifdef HAS_GL -#ifndef D3DCOLOR_RGBA -#define D3DCOLOR_RGBA(r,g,b,a) (r|(g<<8)|(b<<16)|(a<<24)) -#endif -#endif - - // Settings struct - StructSetting** m_structSettings; - unsigned int m_uiVisElements; - - // the action commands ( see Visualisation.h ) - #define VIS_ACTION_NEXT_PRESET 1 - #define VIS_ACTION_PREV_PRESET 2 - #define VIS_ACTION_LOAD_PRESET 3 - #define VIS_ACTION_RANDOM_PRESET 4 - #define VIS_ACTION_LOCK_PRESET 5 - #define VIS_ACTION_RATE_PRESET_PLUS 6 - #define VIS_ACTION_RATE_PRESET_MINUS 7 - #define VIS_ACTION_UPDATE_ALBUMART 8 - #define VIS_ACTION_UPDATE_TRACK 9 - - #define VIS_ACTION_USER 100 - - // Functions that your visualisation must implement - void Create(void* unused, int iPosX, int iPosY, int iWidth, int iHeight, const char* szVisualisationName, - float fPixelRatio, const char *szSubModuleName); - void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); - void AudioData(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); - void Render(); - void Stop(); - bool OnAction(long action, void *param); - void GetInfo(VIS_INFO* pInfo); - void FreeSettings(); - unsigned int GetSettings(StructSetting*** sSet); - void UpdateSetting(int num, StructSetting*** sSet); - void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked); - int GetSubModules(char ***names, char ***paths); - - // function to export the above structure to XBMC - void __declspec(dllexport) get_module(struct Visualisation* pVisz) - { - pVisz->Create = Create; - pVisz->Start = Start; - pVisz->AudioData = AudioData; - pVisz->Render = Render; - pVisz->Stop = Stop; - pVisz->GetInfo = GetInfo; - pVisz->OnAction = OnAction; - pVisz->GetSettings = GetSettings; - pVisz->UpdateSetting = UpdateSetting; - pVisz->GetPresets = GetPresets; - pVisz->GetSubModules = GetSubModules; - pVisz->FreeSettings = FreeSettings; - }; -}; - -#endif diff --git a/xbmc/Application.cpp b/xbmc/Application.cpp index 4f6443e5a3..714c9c14cf 100644 --- a/xbmc/Application.cpp +++ b/xbmc/Application.cpp @@ -167,6 +167,7 @@ #include "GUIWindowScripts.h" #include "GUIWindowWeather.h" #include "GUIWindowLoginScreen.h" +#include "GUIWindowAddonBrowser.h" #include "GUIWindowVisualisation.h" #include "GUIWindowSystemInfo.h" #include "GUIWindowScreensaver.h" @@ -179,7 +180,6 @@ // Dialog includes #include "GUIDialogMusicOSD.h" -#include "GUIDialogVisualisationSettings.h" #include "GUIDialogVisualisationPresetList.h" #include "GUIWindowScriptsInfo.h" #include "GUIDialogNetworkSetup.h" @@ -210,7 +210,7 @@ #include "GUIDialogSmartPlaylistEditor.h" #include "GUIDialogSmartPlaylistRule.h" #include "GUIDialogPictureInfo.h" -#include "GUIDialogPluginSettings.h" +#include "GUIDialogAddonSettings.h" #ifdef HAS_LINUX_NETWORK #include "GUIDialogAccessPoints.h" #endif @@ -782,31 +782,29 @@ CProfile* CApplication::InitDirectoriesLinux() g_settings.m_logFolder = strTempPath; bool bCopySystemPlugins = false; - if (!CDirectory::Exists("special://home/plugins") ) + if (!CDirectory::Exists("special://home/addons/plugins") ) bCopySystemPlugins = true; CDirectory::Create("special://home/"); CDirectory::Create("special://temp/"); CDirectory::Create("special://home/skin"); + CDirectory::Create("special://home/addons"); + CDirectory::Create("special://home/addons/visualizations"); + CDirectory::Create("special://home/addons/scripts"); + CDirectory::Create("special://home/addons/scrapers"); + CDirectory::Create("special://home/addons/screensavers"); + CDirectory::Create("special://home/addons/plugins"); + CDirectory::Create("special://home/addons/libraries"); + CDirectory::Create("special://home/addons/libraries/scrapers"); CDirectory::Create("special://home/media"); - CDirectory::Create("special://home/visualisations"); - CDirectory::Create("special://home/screensavers"); CDirectory::Create("special://home/sounds"); CDirectory::Create("special://home/system"); - CDirectory::Create("special://home/plugins"); - CDirectory::Create("special://home/plugins/video"); - CDirectory::Create("special://home/plugins/music"); - CDirectory::Create("special://home/plugins/pictures"); - CDirectory::Create("special://home/plugins/programs"); - CDirectory::Create("special://home/plugins/weather"); - CDirectory::Create("special://home/scripts"); - CDirectory::Create("special://home/scripts/My Scripts"); // FIXME: both scripts should be in 1 directory - - if (!CFile::Exists("special://home/scripts/Common Scripts")) + + /*if (!CFile::Exists("special://home/scripts/Common Scripts")) { if (symlink( INSTALL_PATH "/scripts", _P("special://home/scripts/Common Scripts").c_str() ) != 0) CLog::Log(LOGERROR, "Failed to create common scripts symlink."); - } + }*/ CDirectory::Create("special://masterprofile"); @@ -818,7 +816,7 @@ CProfile* CApplication::InitDirectoriesLinux() // copy system-wide plugins into userprofile if ( bCopySystemPlugins ) - CUtil::CopyDirRecursive("special://xbmc/plugins", "special://home/plugins"); + CUtil::CopyDirRecursive("special://xbmc/addons/plugins", "special://home/addons/plugins"); } else { @@ -895,25 +893,23 @@ CProfile* CApplication::InitDirectoriesOSX() g_settings.m_logFolder = strTempPath; bool bCopySystemPlugins = false; - if (!CDirectory::Exists("special://home/plugins") ) + if (!CDirectory::Exists("special://home/addons/plugins") ) bCopySystemPlugins = true; CDirectory::Create("special://home/"); CDirectory::Create("special://temp/"); CDirectory::Create("special://home/skin"); + CDirectory::Create("special://home/addons"); + CDirectory::Create("special://home/addons/visualizations"); + CDirectory::Create("special://home/addons/scripts"); + CDirectory::Create("special://home/addons/scrapers"); + CDirectory::Create("special://home/addons/screensavers"); + CDirectory::Create("special://home/addons/plugins"); + CDirectory::Create("special://home/addons/libraries"); + CDirectory::Create("special://home/addons/libraries/scrapers"); CDirectory::Create("special://home/media"); - CDirectory::Create("special://home/visualisations"); - CDirectory::Create("special://home/screensavers"); CDirectory::Create("special://home/sounds"); CDirectory::Create("special://home/system"); - CDirectory::Create("special://home/plugins"); - CDirectory::Create("special://home/plugins/video"); - CDirectory::Create("special://home/plugins/music"); - CDirectory::Create("special://home/plugins/pictures"); - CDirectory::Create("special://home/plugins/programs"); - CDirectory::Create("special://home/plugins/weather"); - CDirectory::Create("special://home/scripts"); - CDirectory::Create("special://home/scripts/My Scripts"); // FIXME: both scripts should be in 1 directory #ifdef __APPLE__ strTempPath = strHomePath + "/scripts"; #else @@ -931,7 +927,7 @@ CProfile* CApplication::InitDirectoriesOSX() // copy system-wide plugins into userprofile if ( bCopySystemPlugins ) - CUtil::CopyDirRecursive("special://xbmc/plugins", "special://home/plugins"); + CUtil::CopyDirRecursive("special://xbmc/addons/plugins", "special://home/addons/plugins"); } else { @@ -993,23 +989,22 @@ CProfile* CApplication::InitDirectoriesWin32() SetEnvironmentVariable("XBMC_PROFILE_USERDATA",_P("special://masterprofile").c_str()); bool bCopySystemPlugins = false; - if (!CDirectory::Exists("special://home/plugins") ) + if (!CDirectory::Exists("special://home/addons/plugins") ) bCopySystemPlugins = true; CDirectory::Create("special://home/"); CDirectory::Create("special://home/skin"); + CDirectory::Create("special://home/addons"); + CDirectory::Create("special://home/addons/visualizations"); + CDirectory::Create("special://home/addons/scripts"); + CDirectory::Create("special://home/addons/scrapers"); + CDirectory::Create("special://home/addons/screensavers"); + CDirectory::Create("special://home/addons/plugins"); + CDirectory::Create("special://home/addons/libraries"); + CDirectory::Create("special://home/addons/libraries/scrapers"); CDirectory::Create("special://home/media"); - CDirectory::Create("special://home/visualisations"); - CDirectory::Create("special://home/screensavers"); CDirectory::Create("special://home/sounds"); CDirectory::Create("special://home/system"); - CDirectory::Create("special://home/plugins"); - CDirectory::Create("special://home/plugins/video"); - CDirectory::Create("special://home/plugins/music"); - CDirectory::Create("special://home/plugins/pictures"); - CDirectory::Create("special://home/plugins/programs"); - CDirectory::Create("special://home/plugins/weather"); - CDirectory::Create("special://home/scripts"); CDirectory::Create("special://masterprofile"); @@ -1022,7 +1017,7 @@ CProfile* CApplication::InitDirectoriesWin32() // copy system-wide plugins into userprofile if ( bCopySystemPlugins ) - CUtil::CopyDirRecursive("special://xbmc/plugins", "special://home/plugins"); + CUtil::CopyDirRecursive("special://xbmc/addons/plugins", "special://home/addons/plugins"); // create user/app data/XBMC/cache CSpecialProtocol::SetTempPath(CUtil::AddFileToFolder(homePath,"cache")); @@ -1109,16 +1104,17 @@ bool CApplication::Initialize() #endif { CDirectory::Create("special://xbmc/scripts"); - CDirectory::Create("special://xbmc/plugins"); - CDirectory::Create("special://xbmc/plugins/music"); - CDirectory::Create("special://xbmc/plugins/video"); - CDirectory::Create("special://xbmc/plugins/pictures"); - CDirectory::Create("special://xbmc/plugins/programs"); CDirectory::Create("special://xbmc/plugins/weather"); CDirectory::Create("special://xbmc/language"); - CDirectory::Create("special://xbmc/visualisations"); + CDirectory::Create("special://xbmc/addons"); + CDirectory::Create("special://xbmc/addons/visualizations"); + CDirectory::Create("special://xbmc/addons/scripts"); + CDirectory::Create("special://xbmc/addons/scrapers"); + CDirectory::Create("special://xbmc/addons/screensavers"); + CDirectory::Create("special://xbmc/addons/plugins"); + CDirectory::Create("special://home/addons/libraries"); + CDirectory::Create("special://home/addons/libraries/scrapers"); CDirectory::Create("special://xbmc/sounds"); - CDirectory::Create(CUtil::AddFileToFolder(g_settings.GetUserDataFolder(),"visualisations")); } StartServices(); @@ -1153,6 +1149,7 @@ bool CApplication::Initialize() g_windowManager.Add(new CGUIWindowVideoPlaylist); // window id = 28 g_windowManager.Add(new CGUIWindowLoginScreen); // window id = 29 g_windowManager.Add(new CGUIWindowSettingsProfile); // window id = 34 + g_windowManager.Add(new CGUIWindowAddonBrowser); // window id = 40 g_windowManager.Add(new CGUIDialogYesNo); // window id = 100 g_windowManager.Add(new CGUIDialogProgress); // window id = 101 g_windowManager.Add(new CGUIDialogKeyboard); // window id = 103 @@ -1172,7 +1169,6 @@ bool CApplication::Initialize() #endif g_windowManager.Add(new CGUIDialogSlider); // window id = 145 g_windowManager.Add(new CGUIDialogMusicOSD); // window id = 120 - g_windowManager.Add(new CGUIDialogVisualisationSettings); // window id = 121 g_windowManager.Add(new CGUIDialogVisualisationPresetList); // window id = 122 g_windowManager.Add(new CGUIDialogVideoSettings); // window id = 123 g_windowManager.Add(new CGUIDialogAudioSubtitleSettings); // window id = 124 @@ -1188,7 +1184,7 @@ bool CApplication::Initialize() g_windowManager.Add(new CGUIDialogSmartPlaylistRule); // window id = 137 g_windowManager.Add(new CGUIDialogBusy); // window id = 138 g_windowManager.Add(new CGUIDialogPictureInfo); // window id = 139 - g_windowManager.Add(new CGUIDialogPluginSettings); // window id = 140 + g_windowManager.Add(new CGUIDialogAddonSettings); // window id = 140 #ifdef HAS_LINUX_NETWORK g_windowManager.Add(new CGUIDialogAccessPoints); // window id = 141 #endif @@ -3141,7 +3137,6 @@ bool CApplication::Cleanup() g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SONGSELECT); g_windowManager.Delete(WINDOW_DIALOG_KARAOKE_SELECTOR); g_windowManager.Delete(WINDOW_DIALOG_MUSIC_OSD); - g_windowManager.Delete(WINDOW_DIALOG_VIS_SETTINGS); g_windowManager.Delete(WINDOW_DIALOG_VIS_PRESET_LIST); g_windowManager.Delete(WINDOW_DIALOG_SELECT); g_windowManager.Delete(WINDOW_DIALOG_OK); @@ -3163,7 +3158,7 @@ bool CApplication::Cleanup() g_windowManager.Delete(WINDOW_DIALOG_SMART_PLAYLIST_RULE); g_windowManager.Delete(WINDOW_DIALOG_BUSY); g_windowManager.Delete(WINDOW_DIALOG_PICTURE_INFO); - g_windowManager.Delete(WINDOW_DIALOG_PLUGIN_SETTINGS); + g_windowManager.Delete(WINDOW_DIALOG_ADDON_SETTINGS); g_windowManager.Delete(WINDOW_DIALOG_ACCESS_POINTS); g_windowManager.Delete(WINDOW_DIALOG_SLIDER); @@ -5229,10 +5224,7 @@ void CApplication::UpdateLibraries() CGUIDialogVideoScan *scanner = (CGUIDialogVideoScan *)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN); VIDEO::SScanSettings settings; if (scanner && !scanner->IsScanning()) - { - SScraperInfo info; - scanner->StartScanning("",info,settings,false); - } + scanner->StartScanning("",ADDON::ScraperPtr(),settings,false); } if (g_guiSettings.GetBool("musiclibrary.updateonstartup")) diff --git a/xbmc/ButtonTranslator.cpp b/xbmc/ButtonTranslator.cpp index f3a2b99acc..055c819da9 100644 --- a/xbmc/ButtonTranslator.cpp +++ b/xbmc/ButtonTranslator.cpp @@ -831,6 +831,7 @@ int CButtonTranslator::TranslateWindowString(const char *szWindow) else if (strWindow.Equals("videofiles")) windowID = WINDOW_VIDEO_FILES; else if (strWindow.Equals("videolibrary")) windowID = WINDOW_VIDEO_NAV; else if (strWindow.Equals("videoplaylist")) windowID = WINDOW_VIDEO_PLAYLIST; + else if (strWindow.Equals("addonbrowser")) windowID = WINDOW_ADDON_BROWSER; else if (strWindow.Equals("systeminfo")) windowID = WINDOW_SYSTEM_INFORMATION; else if (strWindow.Equals("teletext")) windowID = WINDOW_DIALOG_OSD_TELETEXT; else if (strWindow.Equals("guicalibration")) windowID = WINDOW_SCREEN_CALIBRATION; @@ -862,7 +863,6 @@ int CButtonTranslator::TranslateWindowString(const char *szWindow) else if (strWindow.Equals("playercontrols")) windowID = WINDOW_DIALOG_PLAYER_CONTROLS; else if (strWindow.Equals("seekbar")) windowID = WINDOW_DIALOG_SEEK_BAR; else if (strWindow.Equals("musicosd")) windowID = WINDOW_DIALOG_MUSIC_OSD; - else if (strWindow.Equals("visualisationsettings")) windowID = WINDOW_DIALOG_VIS_SETTINGS; else if (strWindow.Equals("visualisationpresetlist")) windowID = WINDOW_DIALOG_VIS_PRESET_LIST; else if (strWindow.Equals("osdvideosettings")) windowID = WINDOW_DIALOG_VIDEO_OSD_SETTINGS; else if (strWindow.Equals("osdaudiosettings")) windowID = WINDOW_DIALOG_AUDIO_OSD_SETTINGS; @@ -893,7 +893,7 @@ int CButtonTranslator::TranslateWindowString(const char *szWindow) else if (strWindow.Equals("musicoverlay")) windowID = WINDOW_MUSIC_OVERLAY; else if (strWindow.Equals("videooverlay")) windowID = WINDOW_VIDEO_OVERLAY; else if (strWindow.Equals("pictureinfo")) windowID = WINDOW_DIALOG_PICTURE_INFO; - else if (strWindow.Equals("pluginsettings")) windowID = WINDOW_DIALOG_PLUGIN_SETTINGS; + else if (strWindow.Equals("addonsettings") || strWindow.Equals("visualisationsettings")) windowID = WINDOW_DIALOG_ADDON_SETTINGS; else if (strWindow.Equals("fullscreeninfo")) windowID = WINDOW_DIALOG_FULLSCREEN_INFO; else if (strWindow.Equals("karaokeselector")) windowID = WINDOW_DIALOG_KARAOKE_SONGSELECT; else if (strWindow.Equals("karaokelargeselector")) windowID = WINDOW_DIALOG_KARAOKE_SELECTOR; diff --git a/xbmc/DllAddon.h b/xbmc/DllAddon.h new file mode 100644 index 0000000000..abeb9107fe --- /dev/null +++ b/xbmc/DllAddon.h @@ -0,0 +1,64 @@ +#pragma once +/* +* Copyright (C) 2005-2009 Team XBMC +* http://www.xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* http://www.gnu.org/copyleft/gpl.html +* +*/ + +#include "DynamicDll.h" +#include "addons/include/xbmc_addon_cpp_dll.h" + +template <typename TheStruct, typename Props> +class DllAddonInterface +{ +public: + virtual void GetAddon(TheStruct* pAddon) =0; + virtual ADDON_STATUS Create(void *cb, Props *info) =0; + virtual ADDON_STATUS GetStatus() =0; + virtual bool HasSettings() =0; + virtual unsigned int GetSettings(StructSetting*** sSet)=0; + virtual void FreeSettings()=0; + virtual ADDON_STATUS SetSetting(const char *settingName, const void *settingValue) =0; + virtual void Remove() =0; +}; + +template <typename TheStruct, typename Props> +class DllAddon : public DllDynamic, public DllAddonInterface<TheStruct, Props> +{ +public: + DECLARE_DLL_WRAPPER_TEMPLATE(DllAddon) + DEFINE_METHOD2(ADDON_STATUS, Create, (void* p1, Props* p2)) + DEFINE_METHOD0(ADDON_STATUS, GetStatus) + DEFINE_METHOD0(bool, HasSettings) + DEFINE_METHOD1(unsigned int, GetSettings, (StructSetting ***p1)) + DEFINE_METHOD0(void, FreeSettings) + DEFINE_METHOD2(ADDON_STATUS, SetSetting, (const char *p1, const void *p2)) + DEFINE_METHOD0(void, Remove) + DEFINE_METHOD1(void, GetAddon, (TheStruct* p1)) + BEGIN_METHOD_RESOLVE() + RESOLVE_METHOD_RENAME(get_addon,GetAddon) + RESOLVE_METHOD(Create) + RESOLVE_METHOD(GetStatus) + RESOLVE_METHOD(SetSetting) + RESOLVE_METHOD(GetSettings) + RESOLVE_METHOD(FreeSettings) + RESOLVE_METHOD(HasSettings) + RESOLVE_METHOD(Remove) + END_METHOD_RESOLVE() +}; + diff --git a/xbmc/FileSystem/AddonsDirectory.cpp b/xbmc/FileSystem/AddonsDirectory.cpp new file mode 100644 index 0000000000..39fc36ca60 --- /dev/null +++ b/xbmc/FileSystem/AddonsDirectory.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2005-2008 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + + +#include "AddonsDirectory.h" +#include "FactoryDirectory.h" +#include "Directory.h" +#include "DirectoryCache.h" +#include "FileItem.h" + +using namespace ADDON; + +namespace XFILE +{ + +CAddonsDirectory::CAddonsDirectory(void) +{ + m_allowPrompting = true; + m_cacheDirectory = DIR_CACHE_ONCE; +} + +CAddonsDirectory::~CAddonsDirectory(void) +{} + +bool CAddonsDirectory::GetDirectory(const CStdString& strPath, CFileItemList &items) +{ + CURL path(strPath); + if (!path.GetProtocol().Equals("addons")) + return false; + + VECADDONS addons; + + if (path.GetPassWord().empty()) + CAddonMgr::Get()->GetAddons(TranslateType(path.GetHostName()), addons); + else + CAddonMgr::Get()->GetAddons(TranslateType(path.GetHostName()), addons, TranslateContent(path.GetPassWord())); + + GenerateListing(path, addons, items); + + return !items.IsEmpty(); +} + +void CAddonsDirectory::GenerateListing(CURL &path, VECADDONS& addons, CFileItemList &items) +{ + items.ClearItems(); + for (unsigned i=0; i < addons.size(); i++) + { + AddonPtr addon = addons[i]; + path.SetFileName(addon->UUID()); + CFileItemPtr pItem(new CFileItem(path.Get(), false)); + pItem->SetLabel(addon->Name()); + pItem->SetLabel2(addon->Summary()); + pItem->SetProperty("Addon.Type", TranslateType(addon->Type())); + pItem->SetProperty("Addon.Name", addon->Name()); + pItem->SetProperty("Addon.Summary", addon->Summary()); + pItem->SetProperty("Addon.Description", addon->Description()); + pItem->SetProperty("Addon.Creator", addon->Author()); + pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); + pItem->SetProperty("Addon.Rating", addon->Stars()); + pItem->SetThumbnailImage(addon->Icon()); + items.Add(pItem); + } + items.FillInDefaultIcons(); + items.Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC); +} + +} + diff --git a/xbmc/ScriptSettings.h b/xbmc/FileSystem/AddonsDirectory.h index 9a81561da4..e002d9e4a3 100644 --- a/xbmc/ScriptSettings.h +++ b/xbmc/FileSystem/AddonsDirectory.h @@ -1,7 +1,6 @@ -#ifndef SCRIPTSETTINGS_H_ -#define SCRIPTSETTINGS_H_ +#pragma once /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2009 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -21,23 +20,28 @@ * */ -#include "PluginSettings.h" +#include "IDirectory.h" +#include "AddonManager.h" -class CScriptSettings : public CBasicSettings +class CURL; + +namespace XFILE { -public: - CScriptSettings(); - virtual ~CScriptSettings(); - bool Load(const CStdString& strPath); - bool Save(void); - static bool SettingsExist(const CStdString& strPath); - virtual CStdString getPath() { return m_scriptPath; } - CScriptSettings& operator =(const CBasicSettings&); -private: - CStdString m_id; - CStdString m_scriptPath; - CStdString m_userFileName; -}; + /*! + \ingroup windows + \brief Get access to shares and it's directories. + */ + class CAddonsDirectory : public IDirectory + { + public: + CAddonsDirectory(void); + virtual ~CAddonsDirectory(void); + virtual bool GetDirectory(const CStdString& strPath, CFileItemList &items); + virtual bool Create(const char* strPath) { return true; } + virtual bool Exists(const char* strPath) { return true; } -#endif + private: + void GenerateListing(CURL &path, ADDON::VECADDONS& addons, CFileItemList &items); + }; +} diff --git a/xbmc/FileSystem/FactoryDirectory.cpp b/xbmc/FileSystem/FactoryDirectory.cpp index 45afde9020..3681f7411c 100644 --- a/xbmc/FileSystem/FactoryDirectory.cpp +++ b/xbmc/FileSystem/FactoryDirectory.cpp @@ -34,12 +34,15 @@ #include "MusicDatabaseDirectory.h" #include "MusicSearchDirectory.h" #include "VideoDatabaseDirectory.h" +#include "AddonsDirectory.h" #include "ShoutcastDirectory.h" #include "LastFMDirectory.h" #include "FTPDirectory.h" #include "HTTPDirectory.h" #include "DAVDirectory.h" #include "Application.h" +#include "StringUtils.h" +#include "utils/Addon.h" #ifdef HAS_FILESYSTEM_SMB #ifdef _WIN32 @@ -115,13 +118,14 @@ IDirectory* CFactoryDirectory::Create(const CStdString& strPath) if (strProtocol.size() == 0 || strProtocol == "file") return new CHDDirectory(); if (strProtocol == "special") return new CSpecialProtocolDirectory(); + if (strProtocol == "addons") return new CAddonsDirectory(); #if defined(HAS_FILESYSTEM_CDDA) && defined(HAS_DVD_DRIVE) if (strProtocol == "cdda") return new CCDDADirectory(); #endif #ifdef HAS_FILESYSTEM if (strProtocol == "iso9660") return new CISO9660Directory(); #endif - if (strProtocol == "plugin") return new CPluginDirectory(); + if (StringUtils::ValidateUUID(url.GetHostName())) return new CPluginDirectory(ADDON::TranslateContent(strProtocol)); if (strProtocol == "zip") return new CZipDirectory(); #ifdef HAS_FILESYSTEM_RAR if (strProtocol == "rar") return new CRarDirectory(); diff --git a/xbmc/FileSystem/Makefile.in b/xbmc/FileSystem/Makefile.in index 413c2a3c0e..ffb26404f6 100644 --- a/xbmc/FileSystem/Makefile.in +++ b/xbmc/FileSystem/Makefile.in @@ -8,7 +8,8 @@ endif CXXFLAGS+=-D__STDC_FORMAT_MACROS \ -SRCS=ASAPFileDirectory.cpp \ +SRCS=AddonsDirectory.cpp \ + ASAPFileDirectory.cpp \ CacheMemBuffer.cpp \ CacheStrategy.cpp \ CDDADirectory.cpp \ diff --git a/xbmc/FileSystem/PluginDirectory.cpp b/xbmc/FileSystem/PluginDirectory.cpp index 8a37f1fdf7..b7c16f57c6 100644 --- a/xbmc/FileSystem/PluginDirectory.cpp +++ b/xbmc/FileSystem/PluginDirectory.cpp @@ -23,11 +23,12 @@ #include "system.h" #include "PluginDirectory.h" #include "Util.h" +#include "utils/AddonManager.h" +#include "utils/IAddon.h" #ifdef HAS_PYTHON #include "lib/libPython/XBPython.h" #endif #include "../utils/SingleLock.h" -#include "PluginSettings.h" #include "GUIWindowManager.h" #include "GUIDialogProgress.h" #include "FileSystem/File.h" @@ -36,15 +37,18 @@ #include "LocalizeStrings.h" #include "utils/log.h" #include "utils/TimeUtils.h" +#include "StringUtils.h" using namespace XFILE; using namespace std; +using namespace ADDON; vector<CPluginDirectory *> CPluginDirectory::globalHandles; CCriticalSection CPluginDirectory::m_handleLock; -CPluginDirectory::CPluginDirectory(void) +CPluginDirectory::CPluginDirectory(const CONTENT_TYPE &content) { + m_content = content; m_fetchComplete = CreateEvent(NULL, false, false, NULL); m_listItems = new CFileItemList; m_fileResult = new CFileItem; @@ -76,29 +80,23 @@ bool CPluginDirectory::StartScript(const CStdString& strPath) { CURL url(strPath); - // path is special://home/plugins/<path from here> - CStdString pathToScript = "special://home/plugins/"; - CUtil::AddFileToFolder(pathToScript, url.GetHostName(), pathToScript); - CUtil::AddFileToFolder(pathToScript, url.GetFileName(), pathToScript); - CUtil::AddFileToFolder(pathToScript, "default.py", pathToScript); + if (!CAddonMgr::Get()->GetAddon(ADDON_PLUGIN, url.GetHostName(), m_addon)) + { + CLog::Log(LOGERROR, "Unable to find plugin %s", url.GetHostName().c_str()); + return false; + } - // base path - CStdString basePath = "plugin://"; - CUtil::AddFileToFolder(basePath, url.GetHostName(), basePath); - CUtil::AddFileToFolder(basePath, url.GetFileName(), basePath); + if (m_addon->HasSettings()) + m_addon->LoadSettings(); - // options + // get options CStdString options = url.GetOptions(); CUtil::RemoveSlashAtEnd(options); // This MAY kill some scripts (eg though with a URL ending with a slash), but // is needed for all others, as XBMC adds slashes to "folders" + url.SetOptions(""); // do this because we can then use the url to generate the basepath + // which is passed to the plugin (and represents the share) - // Load the plugin settings - CLog::Log(LOGDEBUG, "%s - URL for plugin settings: %s", __FUNCTION__, url.GetFileName().c_str() ); - g_currentPluginSettings.Load(url); - - // Load language strings - LoadPluginStrings(url); - + CStdString basePath(url.Get()); // reset our wait event, and grab a new handle ResetEvent(m_fetchComplete); int handle = getNewHandle(this); @@ -117,18 +115,18 @@ bool CPluginDirectory::StartScript(const CStdString& strPath) const char *plugin_argv[] = {basePath.c_str(), strHandle.c_str(), options.c_str(), NULL }; // run the script - CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, pathToScript.c_str(), plugin_argv[0], plugin_argv[1], plugin_argv[2]); + CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, m_addon->Name().c_str(), plugin_argv[0], plugin_argv[1], plugin_argv[2]); bool success = false; #ifdef HAS_PYTHON - if (g_pythonParser.evalFile(pathToScript.c_str(), 3, (const char**)plugin_argv) >= 0) + CStdString file = m_addon->Path() + m_addon->LibName(); + if (g_pythonParser.evalFile(file.c_str(), 3, (const char**)plugin_argv) >= 0) { // wait for our script to finish - CStdString scriptName = url.GetFileName(); - CUtil::RemoveSlashAtEnd(scriptName); - success = WaitOnScriptResult(pathToScript, scriptName); + CStdString scriptName = m_addon->Name(); + success = WaitOnScriptResult(file, scriptName); } else #endif - CLog::Log(LOGERROR, "Unable to run plugin %s", pathToScript.c_str()); + CLog::Log(LOGERROR, "Unable to run plugin %s", m_addon->Name().c_str()); // free our handle removeHandle(handle); @@ -138,7 +136,8 @@ bool CPluginDirectory::StartScript(const CStdString& strPath) bool CPluginDirectory::GetPluginResult(const CStdString& strPath, CFileItem &resultItem) { - CPluginDirectory* newDir = new CPluginDirectory(); + CURL url(strPath); + CPluginDirectory* newDir = new CPluginDirectory(TranslateContent(url.GetProtocol())); bool success = newDir->StartScript(strPath); @@ -202,9 +201,6 @@ void CPluginDirectory::EndOfDirectory(int handle, bool success, bool replaceList if (!dir->m_listItems->HasSortDetails()) dir->m_listItems->AddSortMethod(SORT_METHOD_NONE, 552, LABEL_MASKS("%L", "%D")); - // Unload temporary language strings - ClearPluginStrings(); - // set the event to mark that we're done SetEvent(dir->m_fetchComplete); } @@ -375,9 +371,9 @@ void CPluginDirectory::AddSortMethod(int handle, SORT_METHOD sortMethod) bool CPluginDirectory::GetDirectory(const CStdString& strPath, CFileItemList& items) { CURL url(strPath); - if (url.GetFileName().IsEmpty()) - { // called with no script - should never happen - return GetPluginsDirectory(url.GetHostName(), items); + if (!StringUtils::ValidateUUID(url.GetHostName())) + { // called with no script - we must be browsing root of plugins dir + return GetPluginsDirectory(ADDON::TranslateContent(url.GetHostName()), items); } bool success = this->StartScript(strPath); @@ -391,29 +387,27 @@ bool CPluginDirectory::GetDirectory(const CStdString& strPath, CFileItemList& it bool CPluginDirectory::RunScriptWithParams(const CStdString& strPath) { CURL url(strPath); - if (url.GetFileName().IsEmpty()) // called with no script - should never happen + if (url.GetHostName().IsEmpty()) // called with no script - should never happen return false; - // Load the settings incase they changed while in the plugins directory - g_currentPluginSettings.Load(url); - - // Load language strings - LoadPluginStrings(url); + AddonPtr addon; + if (!CAddonMgr::Get()->GetAddon(ADDON_PLUGIN, url.GetHostName(), addon)) + { + CLog::Log(LOGERROR, "Unable to find plugin %s", url.GetHostName().c_str()); + return false; + } - // path is special://home/plugins/<path from here> - CStdString pathToScript = "special://home/plugins/"; - CUtil::AddFileToFolder(pathToScript, url.GetHostName(), pathToScript); - CUtil::AddFileToFolder(pathToScript, url.GetFileName(), pathToScript); - CUtil::AddFileToFolder(pathToScript, "default.py", pathToScript); + if (addon->HasSettings()) + addon->LoadSettings(); // options CStdString options = url.GetOptions(); CUtil::RemoveSlashAtEnd(options); // This MAY kill some scripts (eg though with a URL ending with a slash), but // is needed for all others, as XBMC adds slashes to "folders" - // base path - CStdString basePath = "plugin://"; - CUtil::AddFileToFolder(basePath, url.GetHostName(), basePath); - CUtil::AddFileToFolder(basePath, url.GetFileName(), basePath); + url.SetOptions(""); // do this because we can then use the url to generate the basepath + // which is passed to the plugin (and represents the share) + + CStdString basePath(url.Get()); // setup our parameters to send the script CStdString strHandle; @@ -425,75 +419,60 @@ bool CPluginDirectory::RunScriptWithParams(const CStdString& strPath) // run the script #ifdef HAS_PYTHON - CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, pathToScript.c_str(), argv[0], argv[1], argv[2]); - if (g_pythonParser.evalFile(pathToScript.c_str(), 3, (const char**)argv) >= 0) + CStdString file = addon->Path() + addon->LibName(); + CLog::Log(LOGDEBUG, "%s - calling plugin %s('%s','%s','%s')", __FUNCTION__, addon->Name().c_str(), argv[0], argv[1], argv[2]); + if (g_pythonParser.evalFile(file.c_str(), 3, (const char**)argv) >= 0) return true; else #endif - CLog::Log(LOGERROR, "Unable to run plugin %s", pathToScript.c_str()); + CLog::Log(LOGERROR, "Unable to run plugin %s", addon->Name().c_str()); return false; } -bool CPluginDirectory::HasPlugins(const CStdString &type) +bool CPluginDirectory::HasPlugins(const CONTENT_TYPE &type) { - CStdString path = "special://home/plugins/"; - CUtil::AddFileToFolder(path, type, path); - CFileItemList items; - if (CDirectory::GetDirectory(path, items, "/", false)) - { - for (int i = 0; i < items.Size(); i++) - { - CFileItemPtr item = items[i]; - if (item->m_bIsFolder && !item->IsParentFolder() && !item->m_bIsShareOrDrive) - { - CStdString defaultPY; - CUtil::AddFileToFolder(item->m_strPath, "default.py", defaultPY); - if (XFILE::CFile::Exists(defaultPY)) - return true; - } - } - } - return false; + return CAddonMgr::Get()->HasAddons(ADDON_PLUGIN, type); } -bool CPluginDirectory::GetPluginsDirectory(const CStdString &type, CFileItemList &items) +bool CPluginDirectory::GetPluginsDirectory(const CONTENT_TYPE &type, CFileItemList &items) { - // retrieve our folder - CStdString pluginsFolder = "special://home/plugins"; - CUtil::AddFileToFolder(pluginsFolder, type, pluginsFolder); - CUtil::AddSlashAtEnd(pluginsFolder); + VECADDONS addons; - if (!CDirectory::GetDirectory(pluginsFolder, items, "*.py", false)) + if(!CAddonMgr::Get()->GetAddons(ADDON_PLUGIN, addons, type)) return false; - items.m_strPath.Replace("special://home/plugins/", "plugin://"); - - // flatten any folders - TODO: Assigning of thumbs - for (int i = 0; i < items.Size(); i++) + for (IVECADDONS it = addons.begin(); it != addons.end(); it++) { - CFileItemPtr item = items[i]; - item->SetThumbnailImage(""); - item->SetCachedProgramThumb(); - if (!item->HasThumbnail()) - item->SetUserProgramThumb(); - if (!item->HasThumbnail()) + CStdString path("plugin://"); + path.append((*it)->UUID()); + + CFileItemPtr newItem(new CFileItem(path,true)); + newItem->SetLabel((*it)->Name()); + + newItem->SetThumbnailImage(""); + newItem->SetCachedProgramThumb(); + if (!newItem->HasThumbnail()) + newItem->SetUserProgramThumb(); + if (!newItem->HasThumbnail()) { - CFileItem item2(item->m_strPath); - CUtil::AddFileToFolder(item->m_strPath,"default.py",item2.m_strPath); + CFileItem item2((*it)->Path()); + CUtil::AddFileToFolder((*it)->Path(), (*it)->LibName(), item2.m_strPath); item2.m_bIsFolder = false; item2.SetCachedProgramThumb(); if (!item2.HasThumbnail()) item2.SetUserProgramThumb(); + if (!item2.HasThumbnail()) + item2.SetThumbnailImage((*it)->Icon()); if (item2.HasThumbnail()) { - XFILE::CFile::Cache(item2.GetThumbnailImage(),item->GetCachedProgramThumb()); - item->SetThumbnailImage(item->GetCachedProgramThumb()); + XFILE::CFile::Cache(item2.GetThumbnailImage(),newItem->GetCachedProgramThumb()); + newItem->SetThumbnailImage(newItem->GetCachedProgramThumb()); } } - item->m_strPath.Replace("special://home/plugins/", "plugin://"); - item->m_strPath.Replace("\\", "/"); + items.Add(newItem); } + return true; } @@ -600,21 +579,23 @@ void CPluginDirectory::SetResolvedUrl(int handle, bool success, const CFileItem SetEvent(dir->m_fetchComplete); } -void CPluginDirectory::SetContent(int handle, const CStdString &strContent) +CStdString CPluginDirectory::GetSetting(int handle, const CStdString &strID) { if (handle < 0 || handle >= (int)globalHandles.size()) { CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__); - return; + return ""; } CPluginDirectory *dir = globalHandles[handle]; - dir->m_listItems->SetContent(strContent); + if(dir->m_addon) + return dir->m_addon->GetSetting(strID); + else + return ""; } -void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, const CStdString &strValue) +void CPluginDirectory::SetSetting(int handle, const CStdString &strID, const CStdString &value) { - CSingleLock lock(m_handleLock); if (handle < 0 || handle >= (int)globalHandles.size()) { CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__); @@ -622,37 +603,33 @@ void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, co } CPluginDirectory *dir = globalHandles[handle]; - dir->m_listItems->SetProperty(strProperty, strValue); + if(dir->m_addon) + dir->m_addon->UpdateSetting(strID, value); } -void CPluginDirectory::LoadPluginStrings(const CURL &url) +void CPluginDirectory::SetContent(int handle, const CStdString &strContent) { - // Path where the plugin resides - CStdString pathToPlugin = "special://home/plugins/"; - CUtil::AddFileToFolder(pathToPlugin, url.GetHostName(), pathToPlugin); - CUtil::AddFileToFolder(pathToPlugin, url.GetFileName(), pathToPlugin); - - // Path where the language strings reside - CStdString pathToLanguageFile = pathToPlugin; - CStdString pathToFallbackLanguageFile = pathToPlugin; - CUtil::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile); - - // Load language strings temporarily - g_localizeStringsTemp.Load(pathToLanguageFile, pathToFallbackLanguageFile); + if (handle < 0 || handle >= (int)globalHandles.size()) + { + CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__); + return; + } + + CPluginDirectory *dir = globalHandles[handle]; + dir->m_listItems->SetContent(strContent); } -void CPluginDirectory::ClearPluginStrings() +void CPluginDirectory::SetProperty(int handle, const CStdString &strProperty, const CStdString &strValue) { - // Unload temporary language strings - g_localizeStringsTemp.Clear(); -} + CSingleLock lock(m_handleLock); + if (handle < 0 || handle >= (int)globalHandles.size()) + { + CLog::Log(LOGERROR, "%s called with an invalid handle.", __FUNCTION__); + return; + } + CPluginDirectory *dir = globalHandles[handle]; + dir->m_listItems->SetProperty(strProperty, strValue); +} diff --git a/xbmc/FileSystem/PluginDirectory.h b/xbmc/FileSystem/PluginDirectory.h index 183bd4e43d..cd201c2ba4 100644 --- a/xbmc/FileSystem/PluginDirectory.h +++ b/xbmc/FileSystem/PluginDirectory.h @@ -28,6 +28,7 @@ #include <string> #include <vector> #include "../utils/CriticalSection.h" +#include "../utils/IAddon.h" class CURL; class CFileItemList; @@ -38,16 +39,14 @@ namespace XFILE class CPluginDirectory : public IDirectory { public: - CPluginDirectory(void); + CPluginDirectory(const CONTENT_TYPE &content); ~CPluginDirectory(void); virtual bool GetDirectory(const CStdString& strPath, CFileItemList& items); virtual bool IsAllowed(const CStdString &strFile) const { return true; }; virtual bool Exists(const char* strPath) { return true; } static bool RunScriptWithParams(const CStdString& strPath); - static bool HasPlugins(const CStdString &type); - bool GetPluginsDirectory(const CStdString &type, CFileItemList &items); - static void LoadPluginStrings(const CURL &url); - static void ClearPluginStrings(); + static bool HasPlugins(const CONTENT_TYPE &type); + bool GetPluginsDirectory(const CONTENT_TYPE &type, CFileItemList &items); bool StartScript(const CStdString& strPath); static bool GetPluginResult(const CStdString& strPath, CFileItem &resultItem); @@ -56,11 +55,15 @@ public: static bool AddItems(int handle, const CFileItemList *items, int totalItems); static void EndOfDirectory(int handle, bool success, bool replaceListing, bool cacheToDisc); static void AddSortMethod(int handle, SORT_METHOD sortMethod); + static CStdString GetSetting(int handle, const CStdString &key); + static void SetSetting(int handle, const CStdString &key, const CStdString &value); static void SetContent(int handle, const CStdString &strContent); static void SetProperty(int handle, const CStdString &strProperty, const CStdString &strValue); static void SetResolvedUrl(int handle, bool success, const CFileItem* resultItem); private: + ADDON::AddonPtr m_addon; + CONTENT_TYPE m_content; bool WaitOnScriptResult(const CStdString &scriptPath, const CStdString &scriptName); static std::vector<CPluginDirectory*> globalHandles; diff --git a/xbmc/GUIDialogPluginSettings.cpp b/xbmc/GUIDialogAddonSettings.cpp index 777939b047..7f0cebf04b 100644 --- a/xbmc/GUIDialogPluginSettings.cpp +++ b/xbmc/GUIDialogAddonSettings.cpp @@ -19,10 +19,12 @@ * */ -#include "GUIDialogPluginSettings.h" +#include "GUIDialogAddonSettings.h" #include "FileSystem/PluginDirectory.h" +#include "utils/IAddon.h" #include "GUIDialogNumeric.h" #include "GUIDialogFileBrowser.h" +#include "GUIDialogOK.h" #include "GUIControlGroupList.h" #include "Util.h" #include "MediaManager.h" @@ -32,18 +34,16 @@ #include "GUIImage.h" #include "FileSystem/Directory.h" #include "VideoInfoScanner.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "GUIWindowManager.h" #include "Application.h" #include "GUIDialogKeyboard.h" #include "FileItem.h" #include "Settings.h" -#include "ScriptSettings.h" -#include "GUISettings.h" -#include "LocalizeStrings.h" using namespace std; -using namespace XFILE; +using namespace ADDON; +using XFILE::CDirectory; #define CONTROL_AREA 2 #define CONTROL_DEFAULT_BUTTON 3 @@ -57,14 +57,14 @@ using namespace XFILE; #define CONTROL_HEADING_LABEL 20 #define CONTROL_START_CONTROL 100 -CGUIDialogPluginSettings::CGUIDialogPluginSettings() - : CGUIDialogBoxBase(WINDOW_DIALOG_PLUGIN_SETTINGS, "DialogPluginSettings.xml") +CGUIDialogAddonSettings::CGUIDialogAddonSettings() + : CGUIDialogBoxBase(WINDOW_DIALOG_ADDON_SETTINGS, "DialogAddonSettings.xml") {} -CGUIDialogPluginSettings::~CGUIDialogPluginSettings(void) +CGUIDialogAddonSettings::~CGUIDialogAddonSettings(void) {} -bool CGUIDialogPluginSettings::OnMessage(CGUIMessage& message) +bool CGUIDialogAddonSettings::OnMessage(CGUIMessage& message) { switch (message.GetMessage()) { @@ -75,16 +75,19 @@ bool CGUIDialogPluginSettings::OnMessage(CGUIMessage& message) if (iControl == ID_BUTTON_OK) { - m_bConfirmed = true; - SaveSettings(); + if (m_changed) + SaveSettings(); + Close(); + return true; } else if (iControl == ID_BUTTON_DEFAULT) SetDefaults(); else bCloseDialog = ShowVirtualKeyboard(iControl); - if (iControl == ID_BUTTON_OK || iControl == ID_BUTTON_CANCEL || bCloseDialog) + if (iControl == ID_BUTTON_CANCEL || bCloseDialog) { + m_changed = false; Close(); return true; } @@ -94,108 +97,64 @@ bool CGUIDialogPluginSettings::OnMessage(CGUIMessage& message) return CGUIDialogBoxBase::OnMessage(message); } -void CGUIDialogPluginSettings::OnInitWindow() +void CGUIDialogAddonSettings::OnInitWindow() { FreeControls(); CreateControls(); CGUIDialogBoxBase::OnInitWindow(); - m_bConfirmed = false; } // \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(CURL& url) +bool CGUIDialogAddonSettings::ShowAndGetInput(const AddonPtr &addon) { - m_url = url; - - // Load language strings temporarily - XFILE::CPluginDirectory::LoadPluginStrings(url); - - // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); - - pDialog->m_strHeading = m_url.GetFileName(); - CUtil::RemoveSlashAtEnd(pDialog->m_strHeading); - pDialog->m_strHeading.Format("$LOCALIZE[1045] - %s", pDialog->m_strHeading.c_str()); - - CPluginSettings settings; - settings.Load(m_url); - pDialog->m_settings = settings; - - pDialog->DoModal(); + if (!addon) + return false; + + bool changed(false); + if (addon->HasSettings()) + { + // Create the dialog + CGUIDialogAddonSettings* pDialog = NULL; + pDialog = (CGUIDialogAddonSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_ADDON_SETTINGS); + if (!pDialog) + return false; + + // Set the heading + CStdString heading; + heading.Format("$LOCALIZE[10004] - %s", addon->Name().c_str()); // "Settings - AddonName" + pDialog->m_strHeading = heading; + + if (addon->LoadSettings()) + { + pDialog->m_changed = false; + pDialog->m_addon = addon; + pDialog->DoModal(); - if(pDialog->m_bConfirmed) - { - settings = pDialog->m_settings; - settings.Save(); + if (pDialog->m_changed) + { + changed = true; + addon->SaveSettings(); + } + } + else + { // couldn't load settings, inform user + CGUIDialogOK::ShowAndGetInput(24000,0,24030,24031); + } } - - return pDialog->m_bConfirmed; -} - -// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(SScraperInfo& info) -{ - // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); - - pDialog->m_settings = info.settings; - pDialog->m_strHeading.Format("$LOCALIZE[20407] - %s", info.strTitle.c_str()); - - pDialog->DoModal(); - if(pDialog->m_bConfirmed) - info.settings.LoadUserXML(static_cast<CScraperSettings&>(pDialog->m_settings).GetSettings()); - - return pDialog->m_bConfirmed; -} - -// \brief Show CGUIDialogOK dialog, then wait for user to dismiss it. -bool CGUIDialogPluginSettings::ShowAndGetInput(CStdString& path) -{ - CUtil::RemoveSlashAtEnd(path); - m_url = CURL(path); - - // Path where the language strings reside - CStdString pathToLanguageFile = path; - CStdString pathToFallbackLanguageFile = path; - CUtil::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile); - CUtil::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile); - CUtil::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile); - - // Load language strings temporarily - g_localizeStringsTemp.Load(pathToLanguageFile, pathToFallbackLanguageFile); - - // Create the dialog - CGUIDialogPluginSettings* pDialog = (CGUIDialogPluginSettings*) g_windowManager.GetWindow(WINDOW_DIALOG_PLUGIN_SETTINGS); - - pDialog->m_strHeading = CUtil::GetFileName(path); - pDialog->m_strHeading.Format("$LOCALIZE[1049] - %s", pDialog->m_strHeading.c_str()); - - CScriptSettings settings; - settings.Load(path); - pDialog->m_settings = settings; - - pDialog->DoModal(); - - if(pDialog->m_bConfirmed) - { - settings = pDialog->m_settings; - settings.Save(); + else + { // addon does not support settings, inform user + CGUIDialogOK::ShowAndGetInput(24000,0,24030,0); } - return pDialog->m_bConfirmed; + return changed; } -bool CGUIDialogPluginSettings::ShowVirtualKeyboard(int iControl) +bool CGUIDialogAddonSettings::ShowVirtualKeyboard(int iControl) { int controlId = CONTROL_START_CONTROL; bool bCloseDialog = false; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + const TiXmlElement *setting = m_addon->GetSettingsXML()->FirstChildElement("setting"); while (setting) { if (controlId == iControl) @@ -320,9 +279,7 @@ bool CGUIDialogPluginSettings::ShowVirtualKeyboard(int iControl) if (setting->Attribute("default")) { CStdString action = setting->Attribute("default"); - CStdString url = m_url.Get(); - // replace $CWD with the url of plugin - action.Replace("$CWD", url); + action.Replace("$CWD", m_addon->Path()); if (option) bCloseDialog = (strcmpi(option, "close") == 0); g_application.getApplicationMessenger().ExecBuiltIn(action); @@ -340,11 +297,11 @@ bool CGUIDialogPluginSettings::ShowVirtualKeyboard(int iControl) } // Go over all the settings and set their values according to the values of the GUI components -bool CGUIDialogPluginSettings::SaveSettings(void) +bool CGUIDialogAddonSettings::SaveSettings(void) { // Retrieve all the values from the GUI components and put them in the model int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + TiXmlElement *setting = m_addon->GetSettingsXML()->FirstChildElement("setting"); while (setting) { CStdString id; @@ -378,7 +335,7 @@ bool CGUIDialogPluginSettings::SaveSettings(void) default: break; } - m_settings.Set(id, value); + m_addon->UpdateSetting(id, value, type); } setting = setting->NextSiblingElement("setting"); controlId++; @@ -386,7 +343,7 @@ bool CGUIDialogPluginSettings::SaveSettings(void) return true; } -void CGUIDialogPluginSettings::FreeControls() +void CGUIDialogAddonSettings::FreeControls() { // clear the category group CGUIControlGroupList *control = (CGUIControlGroupList *)GetControl(CONTROL_AREA); @@ -397,7 +354,7 @@ void CGUIDialogPluginSettings::FreeControls() } } -void CGUIDialogPluginSettings::CreateControls() +void CGUIDialogAddonSettings::CreateControls() { CGUISpinControlEx *pOriginalSpin = (CGUISpinControlEx*)GetControl(CONTROL_DEFAULT_SPIN); CGUIRadioButtonControl *pOriginalRadioButton = (CGUIRadioButtonControl *)GetControl(CONTROL_DEFAULT_RADIOBUTTON); @@ -424,18 +381,11 @@ void CGUIDialogPluginSettings::CreateControls() SET_CONTROL_LABEL(CONTROL_HEADING_LABEL, m_strHeading); // Create our base path, used for type "fileenum" settings - CStdString basepath; - if (m_url.GetProtocol().Equals("plugin")) - { // plugins need to create path - basepath = CUtil::AddFileToFolder("special://home/plugins/", m_url.GetHostName()); - basepath = CUtil::AddFileToFolder(basepath, m_url.GetFileName()); - } - else - basepath = m_url.Get(); + CStdString basepath(m_addon->Path()); CGUIControl* pControl = NULL; int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + const TiXmlElement *setting = m_addon->GetSettingsXML()->FirstChildElement("setting"); while (setting) { const char *type = setting->Attribute("type"); @@ -451,7 +401,12 @@ void CGUIDialogPluginSettings::CreateControls() entries = setting->Attribute("entries"); CStdString label; if (setting->Attribute("label") && atoi(setting->Attribute("label")) > 0) - label.Format("$LOCALIZE[%s]", setting->Attribute("label")); + { + if (m_addon->Parent()) + label.Format("$ADDON[%s %s]", m_addon->Parent()->UUID().c_str(), setting->Attribute("label")); + else + label.Format("$ADDON[%s %s]", m_addon->UUID().c_str(), setting->Attribute("label")); + } else label = setting->Attribute("label"); @@ -474,8 +429,8 @@ void CGUIDialogPluginSettings::CreateControls() ((CGUIButtonControl *)pControl)->SetLabel(label); if (id) { - m_buttonValues[id] = m_settings.Get(id); - CStdString value=m_settings.Get(id); + CStdString value = m_addon->GetSetting(id); + m_buttonValues[id] = value; // get any option to test for hidden const char *option = setting->Attribute("option"); if (option && (strstr(option, "urlencoded"))) @@ -495,7 +450,7 @@ void CGUIDialogPluginSettings::CreateControls() pControl = new CGUIRadioButtonControl(*pOriginalRadioButton); if (!pControl) return; ((CGUIRadioButtonControl *)pControl)->SetLabel(label); - ((CGUIRadioButtonControl *)pControl)->SetSelected(m_settings.Get(id) == "true"); + ((CGUIRadioButtonControl *)pControl)->SetSelected(m_addon->GetSetting(id) == "true"); } else if (strcmpi(type, "enum") == 0 || strcmpi(type, "labelenum") == 0) { @@ -523,7 +478,7 @@ void CGUIDialogPluginSettings::CreateControls() iAdd = atoi(entryVec[i]); if (!lvalues.IsEmpty()) { - CStdString replace = g_localizeStringsTemp.Get(atoi(valuesVec[i])); + CStdString replace = m_addon->GetString(atoi(valuesVec[i])); if (replace.IsEmpty()) replace = g_localizeStrings.Get(atoi(valuesVec[i])); ((CGUISpinControlEx *)pControl)->AddLabel(replace, iAdd); @@ -533,10 +488,10 @@ void CGUIDialogPluginSettings::CreateControls() } if (strcmpi(type, "labelenum") == 0) { // need to run through all our settings and find the one that matches - ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_settings.Get(id)); + ((CGUISpinControlEx*) pControl)->SetValueFromLabel(m_addon->GetSetting(id)); } else - ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_settings.Get(id))); + ((CGUISpinControlEx*) pControl)->SetValue(atoi(m_addon->GetSetting(id))); } else if (strcmpi(type, "fileenum") == 0) @@ -564,7 +519,7 @@ void CGUIDialogPluginSettings::CreateControls() if ((mask.Equals("/") && pItem->m_bIsFolder) || !pItem->m_bIsFolder) { ((CGUISpinControlEx *)pControl)->AddLabel(pItem->GetLabel(), iItem); - if (pItem->GetLabel().Equals(m_settings.Get(id))) + if (pItem->GetLabel().Equals(m_addon->GetSetting(id))) ((CGUISpinControlEx *)pControl)->SetValue(iItem); iItem++; } @@ -597,10 +552,10 @@ void CGUIDialogPluginSettings::CreateControls() } // Go over all the settings and set their enabled condition according to the values of the enabled attribute -void CGUIDialogPluginSettings::EnableControls() +void CGUIDialogAddonSettings::EnableControls() { int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + const TiXmlElement *setting = m_addon->GetSettingsXML()->FirstChildElement("setting"); while (setting) { const CGUIControl* control = GetControl(controlId); @@ -622,7 +577,7 @@ void CGUIDialogPluginSettings::EnableControls() } } -bool CGUIDialogPluginSettings::GetCondition(const CStdString &condition, const int controlId) +bool CGUIDialogAddonSettings::GetCondition(const CStdString &condition, const int controlId) { if (condition.IsEmpty()) return true; @@ -693,7 +648,7 @@ bool CGUIDialogPluginSettings::GetCondition(const CStdString &condition, const i return bCondition; } -bool CGUIDialogPluginSettings::TranslateSingleString(const CStdString &strCondition, vector<CStdString> &condVec) +bool CGUIDialogAddonSettings::TranslateSingleString(const CStdString &strCondition, vector<CStdString> &condVec) { CStdString strTest = strCondition; strTest.ToLower(); @@ -714,10 +669,10 @@ bool CGUIDialogPluginSettings::TranslateSingleString(const CStdString &strCondit } // Go over all the settings and set their default values -void CGUIDialogPluginSettings::SetDefaults() +void CGUIDialogAddonSettings::SetDefaults() { int controlId = CONTROL_START_CONTROL; - TiXmlElement *setting = m_settings.GetPluginRoot()->FirstChildElement("setting"); + const TiXmlElement *setting = m_addon->GetSettingsXML()->FirstChildElement("setting"); while (setting) { const CGUIControl* control = GetControl(controlId); @@ -763,5 +718,3 @@ void CGUIDialogPluginSettings::SetDefaults() EnableControls(); } -CURL CGUIDialogPluginSettings::m_url; - diff --git a/xbmc/GUIDialogPluginSettings.h b/xbmc/GUIDialogAddonSettings.h index 5a3253d0e8..917f3589ba 100644 --- a/xbmc/GUIDialogPluginSettings.h +++ b/xbmc/GUIDialogAddonSettings.h @@ -1,6 +1,4 @@ -#ifndef GUIDIALOG_PLUGIN_SETTINGS_ -#define GUIDIALOG_PLUGIN_SETTINGS_ - +#pragma once /* * Copyright (C) 2005-2008 Team XBMC * http://www.xbmc.org @@ -23,19 +21,15 @@ */ #include "GUIDialogBoxBase.h" -#include "PluginSettings.h" - -struct SScraperInfo; +#include "Addon.h" -class CGUIDialogPluginSettings : public CGUIDialogBoxBase +class CGUIDialogAddonSettings : public CGUIDialogBoxBase { public: - CGUIDialogPluginSettings(void); - virtual ~CGUIDialogPluginSettings(void); + CGUIDialogAddonSettings(void); + virtual ~CGUIDialogAddonSettings(void); virtual bool OnMessage(CGUIMessage& message); - static bool ShowAndGetInput(CURL& url); - static bool ShowAndGetInput(SScraperInfo& info); - static bool ShowAndGetInput(CStdString& path); + static bool ShowAndGetInput(const ADDON::AddonPtr &addon); protected: virtual void OnInitWindow(); @@ -49,12 +43,10 @@ private: bool SaveSettings(void); bool ShowVirtualKeyboard(int iControl); - static CURL m_url; bool TranslateSingleString(const CStdString &strCondition, std::vector<CStdString> &enableVec); - CBasicSettings m_settings; + ADDON::AddonPtr m_addon; CStdString m_strHeading; std::map<CStdString,CStdString> m_buttonValues; + bool m_changed; }; -#endif - diff --git a/xbmc/GUIDialogContentSettings.cpp b/xbmc/GUIDialogContentSettings.cpp index d3009d609d..d46ed21113 100644 --- a/xbmc/GUIDialogContentSettings.cpp +++ b/xbmc/GUIDialogContentSettings.cpp @@ -20,31 +20,29 @@ */ #include "GUIDialogContentSettings.h" -#include "GUIDialogPluginSettings.h" -#include "Util.h" -#include "VideoDatabase.h" -#include "VideoInfoScanner.h" -#include "FileSystem/Directory.h" -#include "FileSystem/MultiPathDirectory.h" +#include "GUIDialogAddonSettings.h" +#include "GUIDialogOK.h" +#include "GUISettings.h" #include "GUIWindowManager.h" -#include "utils/ScraperParser.h" +#include "utils/IAddon.h" #include "FileItem.h" +#include "VideoDatabase.h" +#include "VideoInfoScanner.h" #include "GUISettings.h" -#include "LocalizeStrings.h" -#include "LangCodeExpander.h" #define CONTROL_CONTENT_TYPE 3 #define CONTROL_SCRAPER_LIST 4 #define CONTROL_SCRAPER_SETTINGS 6 #define CONTROL_START 30 -using namespace XFILE; using namespace std; +using namespace ADDON; CGUIDialogContentSettings::CGUIDialogContentSettings(void) : CGUIDialogSettings(WINDOW_DIALOG_CONTENT_SETTINGS, "DialogContentSettings.xml") { m_bNeedSave = false; + m_content = CONTENT_NONE; m_vecItems = new CFileItemList; } @@ -65,313 +63,228 @@ bool CGUIDialogContentSettings::OnMessage(CGUIMessage &message) } break; - case GUI_MSG_ITEM_SELECT: - { - if (message.GetControlId() == CONTROL_SCRAPER_LIST) - { - if (!m_info.strContent.IsEmpty()) - m_info = m_scrapers[m_info.strContent][message.GetParam1()]; - } - } - break; - case GUI_MSG_CLICKED: int iControl = message.GetSenderId(); - if (iControl == 500) - Close(); - if (iControl == 501) - { - m_bNeedSave = false; - Close(); - } if (iControl == CONTROL_CONTENT_TYPE) { - CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(),CONTROL_CONTENT_TYPE); + CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(), CONTROL_CONTENT_TYPE); g_windowManager.SendMessage(msg); - int iSelected = msg.GetParam1(); - - m_bNeedSave = true; - CStdString strLabel; - switch (iSelected) - { - case 0: m_info.strContent.Empty(); - m_info.strPath.Empty(); - m_info.strThumb.Empty(); - m_info.strTitle.Empty(); - OnSettingChanged(0); - SetupPage(); - break; - case 1: strLabel = g_localizeStrings.Get(20342); - m_info = FindDefault("movies", g_guiSettings.GetString("scrapers.moviedefault")); - CreateSettings(); - SetupPage(); - break; - case 2: strLabel = g_localizeStrings.Get(20343); - m_info = FindDefault("tvshows", g_guiSettings.GetString("scrapers.tvshowdefault")); - CreateSettings(); - SetupPage(); - break; - case 3: strLabel = g_localizeStrings.Get(20389); - m_info = FindDefault("musicvideos", g_guiSettings.GetString("scrapers.musicvideodefault")); - CreateSettings(); - SetupPage(); - break; - case 4: strLabel = g_localizeStrings.Get(132); - m_info = FindDefault("albums", g_guiSettings.GetString("musiclibrary.scraper")); - CreateSettings(); - SetupPage(); - break; - } + m_content = (CONTENT_TYPE) msg.GetParam1(); + SetupPage(); } if (iControl == CONTROL_SCRAPER_LIST) { - CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(),CONTROL_SCRAPER_LIST); + CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(), CONTROL_SCRAPER_LIST); g_windowManager.SendMessage(msg); int iSelected = msg.GetParam1(); + AddonPtr last = m_scraper; + m_scraper = m_scrapers[m_content][iSelected]; + + if (!last && m_scraper) + SetupPage(); - m_info = m_scrapers[m_info.strContent][iSelected]; - FillListControl(); - SET_CONTROL_FOCUS(30,0); + m_bNeedSave = m_scraper != last; + CONTROL_ENABLE_ON_CONDITION(CONTROL_SCRAPER_SETTINGS, m_scraper->HasSettings()); + SET_CONTROL_FOCUS(CONTROL_START,0); } - CStdString scraperPath = GetScraperDirectory(m_info); if (iControl == CONTROL_SCRAPER_SETTINGS) { - if (!scraperPath.IsEmpty() && m_info.settings.LoadSettingsXML(scraperPath + m_info.strPath)) - { - CGUIDialogPluginSettings::ShowAndGetInput(m_info); - m_bNeedSave = true; - return true; - } - return false; + m_bNeedSave = CGUIDialogAddonSettings::ShowAndGetInput(m_scraper); + return m_bNeedSave; } - CScraperParser parser; - CStdString strPath; - if (!m_info.strContent.IsEmpty()) - strPath=scraperPath; - if (!strPath.IsEmpty() && parser.Load(strPath + m_info.strPath) - && parser.HasFunction("GetSettings")) - CONTROL_ENABLE(CONTROL_SCRAPER_SETTINGS); - else - CONTROL_DISABLE(CONTROL_SCRAPER_SETTINGS); - break; } return CGUIDialogSettings::OnMessage(message); } void CGUIDialogContentSettings::OnWindowLoaded() { + FillContentTypes(); CGUIDialogSettings::OnWindowLoaded(); +} - CFileItemList items; - CStdString baseDir = GetScraperDirectory(m_info); - if (!baseDir.IsEmpty()) - CDirectory::GetDirectory(baseDir, items, ".xml", false); - - for (int i=0;i<items.Size();++i) +void CGUIDialogContentSettings::SetupPage() +{ + if (m_content == CONTENT_NONE) { - CScraperParser parser; - if (parser.Load(items[i]->m_strPath)) - { - bool IsDefaultScraper = false; - - SScraperInfo info; - info.strTitle = parser.GetName(); - info.strPath = CUtil::GetFileName(items[i]->m_strPath); - info.strThumb = parser.GetThumb(); - info.strContent = parser.GetContent(); - info.strLanguage = parser.GetLanguage(); - info.settings = m_scraperSettings; - - if ( info.strPath == g_guiSettings.GetString("musiclibrary.scraper") - || info.strPath == g_guiSettings.GetString("scrapers.moviedefault") - || info.strPath == g_guiSettings.GetString("scrapers.tvshowdefault") - || info.strPath == g_guiSettings.GetString("scrapers.musicvideodefault")) - { - IsDefaultScraper = true; - } - - map<CStdString,vector<SScraperInfo> >::iterator iter=m_scrapers.find(info.strContent); - if (iter != m_scrapers.end()) - { - if (IsDefaultScraper) - iter->second.insert(iter->second.begin(),info); - else - iter->second.push_back(info); - } - - vector<SScraperInfo> vec; - vec.push_back(info); - m_scrapers.insert(make_pair(info.strContent,vec)); - } + m_bShowScanSettings = false; + SET_CONTROL_HIDDEN(CONTROL_SCRAPER_LIST); + CONTROL_DISABLE(CONTROL_SCRAPER_SETTINGS); } - - // now select the correct scraper - if (!m_info.strContent.IsEmpty()) + else { - map<CStdString,vector<SScraperInfo> >::iterator iter = m_scrapers.find(m_info.strContent); - if (iter != m_scrapers.end()) + FillListControl(); + SET_CONTROL_VISIBLE(CONTROL_SCRAPER_LIST); + if (m_scraper) { - for (vector<SScraperInfo>::iterator iter2 = iter->second.begin();iter2 != iter->second.end();++iter2) - { - if (iter2->strPath == m_info.strPath) - { - m_info = *iter2; - break; - } - } + m_bShowScanSettings = true; + if (m_scraper->Supports(m_content) && m_scraper->HasSettings()) + CONTROL_ENABLE(CONTROL_SCRAPER_SETTINGS); } + else + CONTROL_DISABLE(CONTROL_SCRAPER_SETTINGS); } -} -void CGUIDialogContentSettings::SetupPage() -{ + CreateSettings(); CGUIDialogSettings::SetupPage(); + SET_CONTROL_VISIBLE(CONTROL_CONTENT_TYPE); +} - CGUIMessage msg(GUI_MSG_LABEL_RESET,GetID(),CONTROL_CONTENT_TYPE); - g_windowManager.SendMessage(msg); - CGUIMessage msg2(GUI_MSG_LABEL_ADD,GetID(),CONTROL_CONTENT_TYPE); - - if (!m_info.strContent.Equals("albums")) // none does not apply to music - { - msg2.SetLabel("<"+g_localizeStrings.Get(231)+">"); - msg2.SetParam1(0); - g_windowManager.SendMessage(msg2); - } - - if (m_scrapers.find("movies") != m_scrapers.end()) +void CGUIDialogContentSettings::CreateSettings() +{ + // crappy setting dependencies part 1 + m_settings.clear(); + switch (m_content) { - msg2.SetLabel(g_localizeStrings.Get(20342)); - msg2.SetParam1(1); - g_windowManager.SendMessage(msg2); - if (m_info.strContent.Equals("movies")) + case CONTENT_TVSHOWS: { - SET_CONTROL_LABEL(CONTROL_CONTENT_TYPE,g_localizeStrings.Get(20342)); - CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, 1); + AddBool(1,20345,&m_bRunScan, m_bShowScanSettings); + AddBool(2,20379,&m_bSingleItem, m_bShowScanSettings); + AddBool(3,20432,&m_bNoUpdate, m_bShowScanSettings); } - } - - if (m_scrapers.find("tvshows") != m_scrapers.end()) - { - msg2.SetLabel(g_localizeStrings.Get(20343)); - msg2.SetParam1(2); - g_windowManager.SendMessage(msg2); - if (m_info.strContent.Equals("tvshows")) + break; + case CONTENT_MOVIES: { - CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, 2); + AddBool(1,20345,&m_bRunScan, m_bShowScanSettings); + AddBool(2,20330,&m_bUseDirNames, m_bShowScanSettings); + AddBool(3,20346,&m_bScanRecursive, m_bShowScanSettings && ((m_bUseDirNames && !m_bSingleItem) || !m_bUseDirNames)); + AddBool(4,20383,&m_bSingleItem, m_bShowScanSettings && (m_bUseDirNames && !m_bScanRecursive)); + AddBool(5,20432,&m_bNoUpdate, m_bShowScanSettings); } - } - if (m_scrapers.find("musicvideos") != m_scrapers.end()) - { - msg2.SetLabel(g_localizeStrings.Get(20389)); - msg2.SetParam1(3); - g_windowManager.SendMessage(msg2); - if (m_info.strContent.Equals("musicvideos")) + break; + case CONTENT_MUSICVIDEOS: { - SET_CONTROL_LABEL(CONTROL_CONTENT_TYPE,g_localizeStrings.Get(20389)); - CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, 3); + AddBool(1,20345,&m_bRunScan, m_bShowScanSettings); + AddBool(2,20346,&m_bScanRecursive, m_bShowScanSettings); + AddBool(3,20432,&m_bNoUpdate, m_bShowScanSettings); } - } - if (m_scrapers.find("albums") != m_scrapers.end()) - { - msg2.SetLabel(m_strContentType); - msg2.SetParam1(4); - g_windowManager.SendMessage(msg2); - if (m_info.strContent.Equals("albums")) + break; + case CONTENT_ALBUMS: { - SET_CONTROL_LABEL(CONTROL_CONTENT_TYPE,m_strContentType); - CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, 3); + AddBool(1,20345,&m_bRunScan, m_bShowScanSettings); + } + break; + case CONTENT_NONE: + default: + { + AddBool(1,20380,&m_bExclude, !m_bShowScanSettings); } } - SET_CONTROL_VISIBLE(CONTROL_CONTENT_TYPE); - // now add them scrapers to the list control - if (m_info.strContent.IsEmpty() || m_info.strContent.Equals("None")) - { - CGUIMessage msgReset(GUI_MSG_LABEL_RESET, GetID(), CONTROL_SCRAPER_LIST); - OnMessage(msgReset); - CONTROL_DISABLE(CONTROL_SCRAPER_LIST); - } - else - { - CONTROL_ENABLE(CONTROL_SCRAPER_LIST); - FillListControl(); - } - - OnSettingChanged(0); } -void CGUIDialogContentSettings::CreateSettings() +void CGUIDialogContentSettings::OnSettingChanged(SettingInfo &setting) { - // clear out any old settings - m_settings.clear(); + CreateSettings(); - if (m_info.strContent.IsEmpty() || m_info.strContent.Equals("None")) - { - AddBool(1,20380,&m_bExclude); - } - if (m_info.strContent.Equals("movies")) - { - AddBool(1,20345,&m_bRunScan); - AddBool(2,20330,&m_bUseDirNames); - AddBool(3,20346,&m_bScanRecursive); - AddBool(4,20383,&m_bSingleItem, m_bUseDirNames); - AddBool(5,20432,&m_bUpdate); - } - if (m_info.strContent.Equals("tvshows")) + // crappy setting dependencies part 2 + if (setting.id == 2) // use dir names { - AddBool(1,20345,&m_bRunScan); - AddBool(2,20379,&m_bSingleItem); - AddBool(3,20432,&m_bUpdate); + m_bSingleItem = false; + UpdateSetting(3); // scan recursively + UpdateSetting(4); // single item } - if (m_info.strContent.Equals("musicvideos")) + else if (setting.id == 3) { - AddBool(1,20345,&m_bRunScan); - AddBool(2,20346,&m_bScanRecursive); - AddBool(3,20432,&m_bUpdate); + m_bSingleItem = false; + UpdateSetting(4); } - if (m_info.strContent.Equals("albums")) + else if (setting.id == 4) { - AddBool(1,20345,&m_bRunScan); + m_bScanRecursive = false; + UpdateSetting(3); } + + m_bNeedSave = true; +} + +void CGUIDialogContentSettings::OnOkay() +{ // watch for content change, but same scraper + if (m_content != m_origContent) + m_bNeedSave = true; } -void CGUIDialogContentSettings::OnSettingChanged(unsigned int num) +void CGUIDialogContentSettings::OnCancel() { - // setting has changed - update anything that needs it - if (num >= m_settings.size()) - return; + m_bNeedSave = false; +} - SettingInfo &setting = m_settings.at(num); - OnSettingChanged(setting); +void CGUIDialogContentSettings::OnInitWindow() +{ + m_bNeedSave = false; + CGUIDialogSettings::OnInitWindow(); } -void CGUIDialogContentSettings::OnSettingChanged(SettingInfo &setting) +void CGUIDialogContentSettings::FillContentTypes() { - // check and update anything that needs it - if (setting.id == 1 || setting.id == 2) + CGUIMessage msg(GUI_MSG_LABEL_RESET,GetID(),CONTROL_CONTENT_TYPE); + g_windowManager.SendMessage(msg); + + if (m_content == CONTENT_ALBUMS || m_content == CONTENT_ARTISTS) { - CreateSettings(); - UpdateSetting(1); - UpdateSetting(2); - UpdateSetting(3); - UpdateSetting(4); - UpdateSetting(5); + FillContentTypes(CONTENT_ALBUMS); + FillContentTypes(CONTENT_ARTISTS); + } + else + { + FillContentTypes(CONTENT_MOVIES); + FillContentTypes(CONTENT_TVSHOWS); + FillContentTypes(CONTENT_MUSICVIDEOS); + + // add 'None' to spinner + CGUIMessage msg2(GUI_MSG_LABEL_ADD,GetID(),CONTROL_CONTENT_TYPE); + msg2.SetLabel(TranslateContent(CONTENT_NONE, true)); + msg2.SetParam1((int) CONTENT_NONE); + g_windowManager.SendMessage(msg2); } - m_bNeedSave = true; + CONTROL_SELECT_ITEM(CONTROL_CONTENT_TYPE, (int) m_content); } -void CGUIDialogContentSettings::OnCancel() +void CGUIDialogContentSettings::FillContentTypes(const CONTENT_TYPE &content) { - m_bNeedSave = false; -} + // grab all scrapers which support this content-type + VECADDONS addons; + if (!CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, content)) + return; -void CGUIDialogContentSettings::OnInitWindow() -{ - m_bNeedSave = false; + AddonPtr addon; + CStdString defaultUUID; + CAddonMgr::Get()->GetDefault(ADDON_SCRAPER, addon, content); + if (addon) + defaultUUID = addon->UUID(); - CGUIDialogSettings::OnInitWindow(); - SET_CONTROL_FOCUS(CONTROL_CONTENT_TYPE,0); + for (IVECADDONS it = addons.begin(); it != addons.end(); it++) + { + bool isDefault = ((*it)->UUID() == defaultUUID); + map<CONTENT_TYPE,VECADDONS>::iterator iter=m_scrapers.find(content); + + AddonPtr scraper = (*it)->Clone((*it)); + + if (m_scraper && m_scraper->Parent() && m_scraper->Parent()->UUID() == (*it)->UUID()) + { // don't overwrite preconfigured scraper + scraper = m_scraper; + } + + if (iter != m_scrapers.end()) + { + if (isDefault) + iter->second.insert(iter->second.begin(), scraper); + else + iter->second.push_back(scraper); + } + else + { + VECADDONS vec; + vec.push_back(scraper); + m_scrapers.insert(make_pair(content,vec)); + } + } + + // add CONTENT type to spinner + CGUIMessage msg(GUI_MSG_LABEL_ADD,GetID(),CONTROL_CONTENT_TYPE); + msg.SetLabel(TranslateContent(content, true)); + msg.SetParam1((int) content); + g_windowManager.SendMessage(msg); } void CGUIDialogContentSettings::FillListControl() @@ -381,25 +294,16 @@ void CGUIDialogContentSettings::FillListControl() int iIndex=0; int selectedIndex = 0; m_vecItems->Clear(); - for (vector<SScraperInfo>::iterator iter=m_scrapers.find(m_info.strContent)->second.begin();iter!=m_scrapers.find(m_info.strContent)->second.end();++iter) - { - CFileItemPtr item(new CFileItem(iter->strTitle)); - item->m_strPath = iter->strPath; - - CStdString strLanguage; - - if (iter->strLanguage.Equals("multi")) - strLanguage = g_localizeStrings.Get(21418); - else - g_LangCodeExpander.Lookup(strLanguage, iter->strLanguage); - - item->SetLabel(iter->strTitle + " (" + strLanguage + ")"); - CStdString baseDir = GetScraperDirectory(*iter); - if (!baseDir.IsEmpty()) - item->SetThumbnailImage(baseDir + iter->strThumb); + if (m_scrapers.size() == 0) + return; - if (iter->strPath.Equals(m_info.strPath)) + for (IVECADDONS iter=m_scrapers.find(m_content)->second.begin();iter!=m_scrapers.find(m_content)->second.end();++iter) + { + CFileItemPtr item(new CFileItem((*iter)->Name())); + item->m_strPath = (*iter)->UUID(); + item->SetThumbnailImage((*iter)->Icon()); + if (m_scraper && (*iter)->UUID() == m_scraper->UUID()) { item->Select(true); selectedIndex = iIndex; @@ -416,7 +320,7 @@ void CGUIDialogContentSettings::FillListControl() CFileItemPtr CGUIDialogContentSettings::GetCurrentListItem(int offset) { int currentItem = -1; - if( m_info.strContent.IsEmpty()) + if(m_bExclude) return CFileItemPtr(); for (int i=0;i<m_vecItems->Size();++i ) { @@ -435,7 +339,7 @@ CFileItemPtr CGUIDialogContentSettings::GetCurrentListItem(int offset) return m_vecItems->Get(item); } -bool CGUIDialogContentSettings::ShowForDirectory(const CStdString& strDirectory, SScraperInfo& scraper, VIDEO::SScanSettings& settings, bool& bRunScan) +bool CGUIDialogContentSettings::ShowForDirectory(const CStdString& strDirectory, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, bool& bRunScan) { CVideoDatabase database; database.Open(); @@ -448,128 +352,91 @@ bool CGUIDialogContentSettings::ShowForDirectory(const CStdString& strDirectory, return bResult; } -bool CGUIDialogContentSettings::Show(SScraperInfo& scraper, bool& bRunScan, int iLabel) +bool CGUIDialogContentSettings::Show(ADDON::ScraperPtr& scraper, bool& bRunScan, CONTENT_TYPE musicContext/*=CONTENT_NONE*/) { VIDEO::SScanSettings dummy; - dummy.recurse = -1; - dummy.parent_name = false; - dummy.parent_name_root = false; - dummy.noupdate = false; - return Show(scraper,dummy,bRunScan,iLabel); + return Show(scraper,dummy,bRunScan,musicContext); } -bool CGUIDialogContentSettings::Show(SScraperInfo& scraper, VIDEO::SScanSettings& settings, bool& bRunScan, int iLabel) +bool CGUIDialogContentSettings::Show(ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, bool& bRunScan, CONTENT_TYPE musicContext/*=CONTENT_NONE*/) { CGUIDialogContentSettings *dialog = (CGUIDialogContentSettings *)g_windowManager.GetWindow(WINDOW_DIALOG_CONTENT_SETTINGS); if (!dialog) return false; - dialog->m_info = scraper; - if (iLabel != -1) // to switch between albums and artists - dialog->m_strContentType = g_localizeStrings.Get(iLabel); - - dialog->m_scraperSettings = scraper.settings; + if (musicContext != CONTENT_NONE) + { + dialog->m_content = musicContext; + } + if (scraper) + { + dialog->m_content = scraper->Content(); + dialog->m_origContent = dialog->m_content; + dialog->m_scraper = scraper; + } dialog->m_bRunScan = bRunScan; dialog->m_bScanRecursive = (settings.recurse > 0 && !settings.parent_name) || (settings.recurse > 1 && settings.parent_name); dialog->m_bUseDirNames = settings.parent_name; - dialog->m_bExclude = scraper.strContent.Equals("None"); + dialog->m_bExclude = settings.exclude; dialog->m_bSingleItem = settings.parent_name_root; + dialog->m_bNoUpdate = settings.noupdate; dialog->m_bNeedSave = false; - dialog->m_bUpdate = settings.noupdate; dialog->DoModal(); if (dialog->m_bNeedSave) { - scraper = dialog->m_info; - settings.noupdate = dialog->m_bUpdate; - - if (scraper.strContent.Equals("tvshows")) + scraper = boost::dynamic_pointer_cast<CScraper>(dialog->m_scraper); + CONTENT_TYPE content = dialog->m_content; + if (!scraper || content == CONTENT_NONE) { - settings.parent_name = dialog->m_bSingleItem; - settings.parent_name_root = dialog->m_bSingleItem; - settings.recurse = 0; - - bRunScan = dialog->m_bRunScan; + scraper.reset(); + bRunScan = false; + settings.exclude = dialog->m_bExclude; } - else if (scraper.strContent.Equals("movies")) + else { - if (dialog->m_bUseDirNames) - { - settings.parent_name = true; - settings.parent_name_root = false; - settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 1; + settings.exclude = false; + settings.noupdate = dialog->m_bNoUpdate; + bRunScan = dialog->m_bRunScan; + scraper->m_pathContent = content; - if (dialog->m_bSingleItem) + if (content == CONTENT_TVSHOWS) + { + settings.parent_name = dialog->m_bSingleItem; + settings.parent_name_root = dialog->m_bSingleItem; + settings.recurse = 0; + } + else if (content == CONTENT_MOVIES) + { + if (dialog->m_bUseDirNames) + { + settings.parent_name = true; + settings.parent_name_root = false; + settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 1; + + if (dialog->m_bSingleItem) + { + settings.parent_name_root = true; + settings.recurse = 0; + } + } + else { - settings.parent_name_root = true; - settings.recurse = 0; + settings.parent_name = false; + settings.parent_name_root = false; + settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 0; } } - else + else if (content == CONTENT_MUSICVIDEOS) { settings.parent_name = false; settings.parent_name_root = false; settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 0; } - - bRunScan = dialog->m_bRunScan; } - else if (scraper.strContent.Equals("musicvideos")) - { - settings.parent_name = false; - settings.parent_name_root = false; - settings.recurse = dialog->m_bScanRecursive ? INT_MAX : 0; - - bRunScan = dialog->m_bRunScan; - } - else if (scraper.strContent.Equals("albums")) - { - bRunScan = dialog->m_bRunScan; - } - else if (scraper.strContent.IsEmpty() || scraper.strContent.Equals("None") ) - { - if (dialog->m_bExclude) - scraper.strContent = "None"; - else - scraper.strContent = ""; - - bRunScan = false; - } - - CStdString baseDir = GetScraperDirectory(scraper); - if (!baseDir.IsEmpty() && (!scraper.settings.GetPluginRoot() || scraper.settings.GetSettings().IsEmpty())) - { // load default scraper settings - if (scraper.settings.LoadSettingsXML(baseDir + scraper.strPath)) - scraper.settings.SaveFromDefault(); - } - - return true; } - return false; -} - -SScraperInfo CGUIDialogContentSettings::FindDefault(const CStdString& strType, const CStdString& strDefault) -{ - SScraperInfo result = m_scrapers[strType][0]; // default to first - for (unsigned int i=0;i<m_scrapers[strType].size();++i) - { - if (m_scrapers[strType][i].strPath.Equals(strDefault)) - { - result = m_scrapers[strType][i]; - break; - } - } - - return result; -} - -CStdString CGUIDialogContentSettings::GetScraperDirectory(const SScraperInfo &scraper) -{ - CStdString dir = "video/"; - if (scraper.strContent.Equals("albums")) - dir = "music/"; - else if (scraper.strContent.Equals("None")) - return ""; - return "special://xbmc/system/scrapers/" + dir; + dialog->m_scraper.reset(); + dialog->m_content = dialog->m_origContent = CONTENT_NONE; + return dialog->m_bNeedSave; } diff --git a/xbmc/GUIDialogContentSettings.h b/xbmc/GUIDialogContentSettings.h index fc64cacc6c..22ff4d3fdd 100644 --- a/xbmc/GUIDialogContentSettings.h +++ b/xbmc/GUIDialogContentSettings.h @@ -22,7 +22,9 @@ */ #include "GUIDialogSettings.h" -#include "ScraperSettings.h" +#include "Scraper.h" +#include "utils/AddonManager.h" +#include <vector> namespace VIDEO { @@ -35,38 +37,41 @@ class CGUIDialogContentSettings : public CGUIDialogSettings public: CGUIDialogContentSettings(void); virtual ~CGUIDialogContentSettings(void); - virtual bool OnMessage(CGUIMessage &message); + virtual bool OnMessage(CGUIMessage& message); - static bool Show(SScraperInfo& scraper, bool& bRunScan, int iLabel=-1); - static bool Show(SScraperInfo& scraper, VIDEO::SScanSettings& settings, bool& bRunScan, int iLabel=-1); - static bool ShowForDirectory(const CStdString& strDirectory, SScraperInfo& scraper, VIDEO::SScanSettings& settings, bool& bRunScan); + static bool Show(ADDON::ScraperPtr& scraper, bool& bRunScan, CONTENT_TYPE musicContext = CONTENT_NONE); + static bool Show(ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, bool& bRunScan, CONTENT_TYPE musicContext = CONTENT_NONE); + static bool ShowForDirectory(const CStdString& strDirectory, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, bool& bRunScan); virtual bool HasListItems() const { return true; }; virtual CFileItemPtr GetCurrentListItem(int offset = 0); protected: + virtual void OnOkay(); virtual void OnCancel(); virtual void OnWindowLoaded(); virtual void OnInitWindow(); virtual void SetupPage(); virtual void CreateSettings(); + void FillContentTypes(); + void FillContentTypes(const CONTENT_TYPE& content); + void AddContentType(const CONTENT_TYPE& content); void FillListControl(); - void OnSettingChanged(unsigned int setting); - virtual void OnSettingChanged(SettingInfo &setting); - SScraperInfo FindDefault(const CStdString& strType, const CStdString& strDefault); - static CStdString GetScraperDirectory(const SScraperInfo& scraper); + virtual void OnSettingChanged(SettingInfo& setting); bool m_bNeedSave; + bool m_bShowScanSettings; bool m_bRunScan; bool m_bScanRecursive; bool m_bUseDirNames; bool m_bSingleItem; bool m_bExclude; - bool m_bUpdate; - std::map<CStdString,std::vector<SScraperInfo> > m_scrapers; // key = content type + bool m_bNoUpdate; + std::map<CONTENT_TYPE, ADDON::VECADDONS> m_scrapers; CFileItemList* m_vecItems; - SScraperInfo m_info; - CScraperSettings m_scraperSettings; // needed so we have a basis - CStdString m_strContentType; // used for artist/albums + CStdString m_strContentType; + ADDON::AddonPtr m_scraper; + CStdString m_defaultScraper; + CONTENT_TYPE m_content; + CONTENT_TYPE m_origContent; }; - diff --git a/xbmc/GUIDialogContextMenu.cpp b/xbmc/GUIDialogContextMenu.cpp index b144d70484..54bc46b7ea 100644 --- a/xbmc/GUIDialogContextMenu.cpp +++ b/xbmc/GUIDialogContextMenu.cpp @@ -36,11 +36,13 @@ #include "MediaManager.h" #include "GUIWindowManager.h" #include "GUIDialogYesNo.h" +#include "utils/AddonManager.h" #include "FileItem.h" #include "FileSystem/File.h" #include "Picture.h" #include "Settings.h" #include "LocalizeStrings.h" +#include "StringUtils.h" #ifdef _WIN32 #include "WIN32Util.h" @@ -289,11 +291,23 @@ void CGUIDialogContextMenu::GetContextButtons(const CStdString &type, const CFil { if (share) { - if (!share->m_ignore) + // Note. from now on, remove source & disable plugin should mean the same thing + //TODO might be smart to also combine editing source & plugin settings into one concept/dialog + + CURL url(share->strPath); + bool isUUID = StringUtils::ValidateUUID(url.GetHostName()); + if (!share->m_ignore && !isUUID) buttons.Add(CONTEXT_BUTTON_EDIT_SOURCE, 1027); // Edit Source + else + { + ADDON::AddonPtr plugin; + if (ADDON::CAddonMgr::Get()->GetAddon(ADDON::ADDON_PLUGIN, url.GetHostName(), plugin)) + if (plugin->HasSettings()) + buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045); // Plugin Settings + } buttons.Add(CONTEXT_BUTTON_SET_DEFAULT, 13335); // Set as Default if (!share->m_ignore) - buttons.Add(CONTEXT_BUTTON_REMOVE_SOURCE, 522); // Remove Source + buttons.Add(CONTEXT_BUTTON_REMOVE_SOURCE, 522); // Remove Source / disable plugin buttons.Add(CONTEXT_BUTTON_SET_THUMB, 20019); } @@ -383,6 +397,7 @@ bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileI return CGUIDialogMediaSource::ShowAndEditMediaSource(type, *share); case CONTEXT_BUTTON_REMOVE_SOURCE: + { if (g_settings.m_iLastLoadedProfileIndex == 0) { if (!g_passwordManager.IsMasterLockUnlocked(true)) @@ -395,8 +410,14 @@ bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileI if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteSources() && !g_passwordManager.IsProfileLockUnlocked()) return false; } - // prompt user if they want to really delete the source - if (CGUIDialogYesNo::ShowAndGetInput(751, 0, 750, 0)) + // prompt user if they want to really delete the source/disable the plugin + bool yes(false); + bool plugin = item->IsPlugin(); + if (plugin) + yes = CGUIDialogYesNo::ShowAndGetInput(24009, 24010, 24011, 0); + else + yes = CGUIDialogYesNo::ShowAndGetInput(751, 0, 750, 0); + if (yes) { // check default before we delete, as deletion will kill the share object CStdString defaultSource(GetDefaultShareNameByType(type)); if (!defaultSource.IsEmpty()) @@ -404,13 +425,16 @@ bool CGUIDialogContextMenu::OnContextButton(const CStdString &type, const CFileI if (share->strName.Equals(defaultSource)) ClearDefault(type); } - - // delete this share - g_settings.DeleteSource(type, share->strName, share->strPath); - return true; + if (plugin) + { + CURL path(share->strPath); + ADDON::CAddonMgr::Get()->DisableAddon(path.GetHostName()); + } + else + g_settings.DeleteSource(type, share->strName, share->strPath); } - break; - + return true; + } case CONTEXT_BUTTON_SET_DEFAULT: if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteSources() && !g_passwordManager.IsProfileLockUnlocked()) return false; diff --git a/xbmc/GUIDialogLockSettings.cpp b/xbmc/GUIDialogLockSettings.cpp index ed1bee55a7..e52b5db882 100644 --- a/xbmc/GUIDialogLockSettings.cpp +++ b/xbmc/GUIDialogLockSettings.cpp @@ -116,6 +116,7 @@ void CGUIDialogLockSettings::CreateSettings() AddBool(6,20041,&m_bLockPrograms); AddBool(7,20042,&m_bLockFiles); AddBool(8,20043,&m_bLockSettings); + AddBool(9,24090,&m_bLockAddOnManager); EnableDetails(m_iLock != LOCK_MODE_EVERYONE); } } @@ -236,10 +237,10 @@ bool CGUIDialogLockSettings::ShowAndGetUserAndPassword(CStdString& strUser, CStd bool CGUIDialogLockSettings::ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, int iHeader) { bool f; - return ShowAndGetLock(iLockMode,strPassword,f,f,f,f,f,f,iHeader,false,false); + return ShowAndGetLock(iLockMode,strPassword,f,f,f,f,f,f,f,iHeader,false,false); } -bool CGUIDialogLockSettings::ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, bool& bLockMusic, bool& bLockVideo, bool& bLockPictures, bool& bLockPrograms, bool& bLockFiles, bool& bLockSettings, int iButtonLabel, bool bConditional, bool bDetails) +bool CGUIDialogLockSettings::ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, bool& bLockMusic, bool& bLockVideo, bool& bLockPictures, bool& bLockPrograms, bool& bLockFiles, bool& bLockSettings, bool& bLockAddOnManager, int iButtonLabel, bool bConditional, bool bDetails) { CGUIDialogLockSettings *dialog = (CGUIDialogLockSettings *)g_windowManager.GetWindow(WINDOW_DIALOG_LOCK_SETTINGS); if (!dialog) return false; @@ -257,6 +258,7 @@ bool CGUIDialogLockSettings::ShowAndGetLock(LockType& iLockMode, CStdString& str dialog->m_bLockPictures = bLockPictures; dialog->m_bLockFiles = bLockFiles; dialog->m_bLockSettings = bLockSettings; + dialog->m_bLockAddOnManager = bLockAddOnManager; } dialog->m_bDetails = bDetails; dialog->DoModal(); @@ -279,6 +281,7 @@ bool CGUIDialogLockSettings::ShowAndGetLock(LockType& iLockMode, CStdString& str bLockPictures = dialog->m_bLockPictures; bLockFiles = dialog->m_bLockFiles; bLockSettings = dialog->m_bLockSettings; + bLockAddOnManager = dialog->m_bLockAddOnManager; } return true; } diff --git a/xbmc/GUIDialogLockSettings.h b/xbmc/GUIDialogLockSettings.h index cab22d8127..91432e16c9 100644 --- a/xbmc/GUIDialogLockSettings.h +++ b/xbmc/GUIDialogLockSettings.h @@ -31,7 +31,7 @@ public: virtual ~CGUIDialogLockSettings(void); virtual bool OnMessage(CGUIMessage &message); static bool ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, int iHeader=20091); - static bool ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, bool& bLockMusic, bool& bLockVideo, bool& bLockPictures, bool& bLockPrograms, bool& bLockFiles, bool& bLockSettings, int iButtonLabel=20091,bool bConditional=false, bool bDetails=true); + static bool ShowAndGetLock(LockType& iLockMode, CStdString& strPassword, bool& bLockMusic, bool& bLockVideo, bool& bLockPictures, bool& bLockPrograms, bool& bLockFiles, bool& bLockSettings, bool& bLockAddOnManager, int iButtonLabel=20091,bool bConditional=false, bool bDetails=true); static bool ShowAndGetUserAndPassword(CStdString& strUser, CStdString& strPassword, const CStdString& strURL, bool *saveUserDetails); protected: virtual void OnCancel(); @@ -57,6 +57,7 @@ protected: bool m_bLockFiles; bool m_bLockSettings; bool *m_saveUserDetails; + bool m_bLockAddOnManager; }; diff --git a/xbmc/GUIDialogMediaSource.cpp b/xbmc/GUIDialogMediaSource.cpp index 75bd7492ef..0f6ad08048 100644 --- a/xbmc/GUIDialogMediaSource.cpp +++ b/xbmc/GUIDialogMediaSource.cpp @@ -108,8 +108,6 @@ bool CGUIDialogMediaSource::OnMessage(CGUIMessage& message) m_confirmed = false; m_bRunScan = false; m_bNameChanged=false; - m_settings.parent_name = false; - m_settings.recurse = 0; UpdateButtons(); } break; @@ -166,7 +164,7 @@ bool CGUIDialogMediaSource::ShowAndAddMediaSource(const CStdString &type) if (type == "video") { if (dialog->m_bRunScan) - CGUIWindowVideoBase::OnScan(share.strPath,dialog->m_info,dialog->m_settings); + CGUIWindowVideoBase::OnScan(share.strPath,ADDON::ScraperPtr(),dialog->m_settings); } } @@ -281,7 +279,7 @@ void CGUIDialogMediaSource::OnPathBrowse(int item) extraShares.push_back(share1); } // add the plugins dir as needed - if (CPluginDirectory::HasPlugins("music")) + if (ADDON::CAddonMgr::Get()->HasAddons(ADDON::ADDON_PLUGIN, CONTENT_ALBUMS)) { share1.strPath = "plugin://music/"; share1.strName = g_localizeStrings.Get(1038); // Music Plugins @@ -321,7 +319,7 @@ void CGUIDialogMediaSource::OnPathBrowse(int item) extraShares.push_back(share1); // add the plugins dir as needed - if (CPluginDirectory::HasPlugins("video")) + if (ADDON::CAddonMgr::Get()->HasAddons(ADDON::ADDON_PLUGIN, CONTENT_MOVIES)) { share1.strPath = "plugin://video/"; share1.strName = g_localizeStrings.Get(1037); // Video Plugins @@ -352,7 +350,7 @@ void CGUIDialogMediaSource::OnPathBrowse(int item) extraShares.push_back(share1); // add the plugins dir as needed - if (CPluginDirectory::HasPlugins("pictures")) + if (ADDON::CAddonMgr::Get()->HasAddons(ADDON::ADDON_PLUGIN, CONTENT_PICTURES)) { share1.strPath = "plugin://pictures/"; share1.strName = g_localizeStrings.Get(1039); // Picture Plugins @@ -361,7 +359,7 @@ void CGUIDialogMediaSource::OnPathBrowse(int item) } else if (m_type == "programs") { - if (CPluginDirectory::HasPlugins("programs")) + if (ADDON::CAddonMgr::Get()->HasAddons(ADDON::ADDON_PLUGIN, CONTENT_PROGRAMS)) { CMediaSource share2; share2.strPath = "plugin://programs/"; @@ -421,7 +419,7 @@ void CGUIDialogMediaSource::OnOK() if (share.strPath.Left(9).Equals("plugin://")) { CStdString strPath=share.strPath; - strPath.Replace("plugin://","special://home/plugins/"); + strPath.Replace("plugin://","special://home/addons/plugins/"); CFileItem item(strPath,true); item.SetCachedProgramThumb(); if (!item.HasThumbnail()) diff --git a/xbmc/GUIDialogMediaSource.h b/xbmc/GUIDialogMediaSource.h index 84f7a62933..7c9082ba6e 100644 --- a/xbmc/GUIDialogMediaSource.h +++ b/xbmc/GUIDialogMediaSource.h @@ -61,7 +61,7 @@ protected: CStdString m_name; CFileItemList* m_paths; bool m_confirmed; - SScraperInfo m_info; + ADDON::ScraperPtr m_info; bool m_bRunScan; bool m_bNameChanged; diff --git a/xbmc/GUIDialogMusicOSD.cpp b/xbmc/GUIDialogMusicOSD.cpp index f1711ecc31..f64e65e144 100644 --- a/xbmc/GUIDialogMusicOSD.cpp +++ b/xbmc/GUIDialogMusicOSD.cpp @@ -30,6 +30,8 @@ #define CONTROL_LOCK_BUTTON 501 #define CONTROL_VIS_CHOOSER 503 +using ADDON::CVisualisation; + CGUIDialogMusicOSD::CGUIDialogMusicOSD(void) : CGUIDialog(WINDOW_DIALOG_MUSIC_OSD, "MusicOSD.xml") { @@ -55,8 +57,7 @@ bool CGUIDialogMusicOSD::OnMessage(CGUIMessage &message) if (msg.GetParam1() == 0) g_guiSettings.SetString("musicplayer.visualisation", "None"); else - g_guiSettings.SetString("musicplayer.visualisation", - CVisualisation::GetCombinedName( strLabel )); + g_guiSettings.SetString("musicplayer.visualisation", strLabel); // hide the control and reset focus SET_CONTROL_HIDDEN(CONTROL_VIS_CHOOSER); SET_CONTROL_FOCUS(CONTROL_VIS_BUTTON, 0); diff --git a/xbmc/GUIDialogMusicOSD.h b/xbmc/GUIDialogMusicOSD.h index b3654a20d2..a644684ea3 100644 --- a/xbmc/GUIDialogMusicOSD.h +++ b/xbmc/GUIDialogMusicOSD.h @@ -22,7 +22,11 @@ */ #include "GUIDialog.h" -#include "visualizations/Visualisation.h" + +namespace ADDON +{ + class CVisualisation; +} class CGUIDialogMusicOSD : public CGUIDialog @@ -36,5 +40,5 @@ public: protected: virtual bool OnMouseEvent(const CPoint &point, const CMouseEvent &event); virtual void OnInitWindow(); - CVisualisation *m_pVisualisation; + ADDON::CVisualisation *m_pVisualisation; }; diff --git a/xbmc/GUIDialogProfileSettings.cpp b/xbmc/GUIDialogProfileSettings.cpp index 7a026397eb..f11582bd00 100644 --- a/xbmc/GUIDialogProfileSettings.cpp +++ b/xbmc/GUIDialogProfileSettings.cpp @@ -263,7 +263,7 @@ void CGUIDialogProfileSettings::OnSettingChanged(SettingInfo &setting) if (g_settings.m_vecProfiles[0].getLockMode() == LOCK_MODE_EVERYONE) return; } - if (CGUIDialogLockSettings::ShowAndGetLock(m_iLockMode,m_strLockCode,m_bLockMusic,m_bLockVideo,m_bLockPictures,m_bLockPrograms,m_bLockFiles,m_bLockSettings,m_bIsDefault?12360:20068,g_settings.m_vecProfiles[0].getLockMode() == LOCK_MODE_EVERYONE || m_bIsDefault)) + if (CGUIDialogLockSettings::ShowAndGetLock(m_iLockMode,m_strLockCode,m_bLockMusic,m_bLockVideo,m_bLockPictures,m_bLockPrograms,m_bLockFiles,m_bLockSettings,m_bLockAddOnManager,m_bIsDefault?12360:20068,g_settings.m_vecProfiles[0].getLockMode() == LOCK_MODE_EVERYONE || m_bIsDefault)) m_bNeedSave = true; } else @@ -300,6 +300,7 @@ bool CGUIDialogProfileSettings::ShowForProfile(unsigned int iProfile, bool bDeta dialog->m_iDbMode = 2; dialog->m_iLockMode = LOCK_MODE_EVERYONE; dialog->m_iSourcesMode = 2; + dialog->m_bLockAddOnManager = true; dialog->m_bLockSettings = true; dialog->m_bLockMusic = false; dialog->m_bLockVideo = false; @@ -332,6 +333,7 @@ bool CGUIDialogProfileSettings::ShowForProfile(unsigned int iProfile, bool bDeta dialog->m_bLockPrograms = g_settings.m_vecProfiles[iProfile].programsLocked(); dialog->m_bLockPictures = g_settings.m_vecProfiles[iProfile].picturesLocked(); dialog->m_bLockSettings = g_settings.m_vecProfiles[iProfile].settingsLocked(); + dialog->m_bLockAddOnManager = g_settings.m_vecProfiles[iProfile].addonmanagerLocked(); dialog->m_bIsNewUser = false; } dialog->DoModal(); @@ -421,6 +423,7 @@ bool CGUIDialogProfileSettings::ShowForProfile(unsigned int iProfile, bool bDeta g_settings.m_vecProfiles[iProfile].setMusicLocked(dialog->m_bLockMusic); g_settings.m_vecProfiles[iProfile].setVideoLocked(dialog->m_bLockVideo); g_settings.m_vecProfiles[iProfile].setSettingsLocked(dialog->m_bLockSettings); + g_settings.m_vecProfiles[iProfile].setAddonManagerLocked(dialog->m_bLockAddOnManager); g_settings.m_vecProfiles[iProfile].setFilesLocked(dialog->m_bLockFiles); g_settings.m_vecProfiles[iProfile].setPicturesLocked(dialog->m_bLockPictures); g_settings.m_vecProfiles[iProfile].setProgramsLocked(dialog->m_bLockPrograms); diff --git a/xbmc/GUIDialogProfileSettings.h b/xbmc/GUIDialogProfileSettings.h index 48bfd9867e..470dabcab5 100644 --- a/xbmc/GUIDialogProfileSettings.h +++ b/xbmc/GUIDialogProfileSettings.h @@ -60,6 +60,7 @@ protected: bool m_bLockFiles; bool m_bLockPictures; bool m_bLockPrograms; + bool m_bLockAddOnManager; CStdString m_strDefaultImage; }; diff --git a/xbmc/GUIDialogVideoScan.cpp b/xbmc/GUIDialogVideoScan.cpp index 6b023050b3..5295d02333 100644 --- a/xbmc/GUIDialogVideoScan.cpp +++ b/xbmc/GUIDialogVideoScan.cpp @@ -115,7 +115,7 @@ void CGUIDialogVideoScan::OnSetTitle(const CStdString& strTitle) m_strTitle = strTitle; } -void CGUIDialogVideoScan::StartScanning(const CStdString& strDirectory, const SScraperInfo& info, const SScanSettings& settings, bool bUpdateAll) +void CGUIDialogVideoScan::StartScanning(const CStdString& strDirectory, const ADDON::ScraperPtr& info, const SScanSettings& settings, bool bUpdateAll) { m_ScanState = PREPARING; diff --git a/xbmc/GUIDialogVideoScan.h b/xbmc/GUIDialogVideoScan.h index b0102afaf0..2bd8f0b12c 100644 --- a/xbmc/GUIDialogVideoScan.h +++ b/xbmc/GUIDialogVideoScan.h @@ -33,7 +33,7 @@ public: virtual bool OnMessage(CGUIMessage& message); virtual void FrameMove(); - void StartScanning(const CStdString& strDirectory, const SScraperInfo& info, const VIDEO::SScanSettings& settings, bool bUpdateAll); + void StartScanning(const CStdString& strDirectory, const ADDON::ScraperPtr& info, const VIDEO::SScanSettings& settings, bool bUpdateAll); bool IsScanning(); void StopScanning(); diff --git a/xbmc/GUIDialogVisualisationPresetList.cpp b/xbmc/GUIDialogVisualisationPresetList.cpp index 7a870f33fa..5c0bb95800 100644 --- a/xbmc/GUIDialogVisualisationPresetList.cpp +++ b/xbmc/GUIDialogVisualisationPresetList.cpp @@ -20,9 +20,9 @@ */ #include "GUIDialogVisualisationPresetList.h" +#include "visualizations/Visualisation.h" #include "GUIWindowManager.h" #include "GUIListContainer.h" -#include "GUISettings.h" #include "GUIUserMessages.h" #include "FileItem.h" #include "LocalizeStrings.h" @@ -31,6 +31,8 @@ #define CONTROL_PRESETS_LABEL 3 #define CONTROL_NONE_AVAILABLE 4 +using ADDON::CVisualisation; + CGUIDialogVisualisationPresetList::CGUIDialogVisualisationPresetList(void) : CGUIDialog(WINDOW_DIALOG_VIS_PRESET_LIST, "VisualisationPresetList.xml") { @@ -57,8 +59,8 @@ bool CGUIDialogVisualisationPresetList::OnMessage(CGUIMessage &message) if (pList) { int iItem = pList->GetSelectedItem(); - if (m_pVisualisation) - m_pVisualisation->OnAction(CVisualisation::VIS_ACTION_LOAD_PRESET, (void *)&iItem); + if (m_viz) + m_viz->OnAction(VIS_ACTION_LOAD_PRESET, (void *)&iItem); } return true; } @@ -70,68 +72,76 @@ bool CGUIDialogVisualisationPresetList::OnMessage(CGUIMessage &message) CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0); g_windowManager.SendMessage(msg); - SetVisualisation((CVisualisation *)msg.GetPointer()); + if (msg.GetPointer()) + { + SetVisualisation((CVisualisation*)msg.GetPointer()); + } return true; } break; case GUI_MSG_WINDOW_DEINIT: case GUI_MSG_VISUALISATION_UNLOADING: { - m_pVisualisation = NULL; + m_viz = NULL; CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST); OnMessage(msg); - m_vecPresets->Clear(); + Update(); } break; case GUI_MSG_VISUALISATION_LOADED: { if (message.GetPointer()) { - SetVisualisation((CVisualisation *)message.GetPointer()); + SetVisualisation((CVisualisation*)message.GetPointer()); } } } return CGUIDialog::OnMessage(message); } +void CGUIDialogVisualisationPresetList::SetVisualisation(CVisualisation* vis) +{ + m_viz = NULL; + if (vis) + { + m_viz = vis; + Update(); + } +} + void CGUIDialogVisualisationPresetList::FrameMove() { - char **presets = NULL; - int numPresets = 0; - int currentPreset = 0; - bool locked = false; - if (m_pVisualisation) - m_pVisualisation->GetPresets(&presets, ¤tPreset, &numPresets, &locked); - if (currentPreset != m_currentPreset) - { // current preset changed... - m_vecPresets->Get(m_currentPreset)->Select(false); - m_currentPreset = currentPreset; - m_vecPresets->Get(m_currentPreset)->Select(true); + //FIXME we shouldn't have to check preset each frame + // a viz callback could push GUI_MSG_VISUALISATION_UPDATED + if (m_viz) + { + unsigned preset = m_viz->GetPreset(); + if (preset != m_currentPreset) + { + m_vecPresets->Get(m_currentPreset)->Select(false); + m_currentPreset = preset; + m_vecPresets->Get(m_currentPreset)->Select(true); + } } CGUIDialog::FrameMove(); } -void CGUIDialogVisualisationPresetList::SetVisualisation(CVisualisation *pVisualisation) +void CGUIDialogVisualisationPresetList::Update() { - m_pVisualisation = pVisualisation; m_vecPresets->Clear(); - if (m_pVisualisation) + CStdString strHeading; + if (m_viz) { + strHeading.Format(g_localizeStrings.Get(13407).c_str(), m_viz->Name().c_str()); + //clear filelist CGUIMessage msg(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST); OnMessage(msg); - char **presets = NULL; - int numPresets = 0; - m_currentPreset = 0; - bool locked = false; - m_pVisualisation->GetPresets(&presets, &m_currentPreset, &numPresets, &locked); - if (presets) + std::vector<CStdString> presets; + if (m_viz->GetPresetList(presets)) { - //clear filelist - CGUIMessage msg2(GUI_MSG_LABEL_RESET, GetID(), CONTROL_LIST); - OnMessage(msg2); - m_vecPresets->Clear(); - for (int i = 0; i < numPresets; i++) + m_currentPreset = m_viz->GetPreset(); + for (unsigned i = 0; i < presets.size(); i++) { CFileItemPtr pItem(new CFileItem(presets[i])); if (i == m_currentPreset) @@ -144,16 +154,10 @@ void CGUIDialogVisualisationPresetList::SetVisualisation(CVisualisation *pVisual OnMessage(msg); } } - // update our settings label - CStdString strVis = g_guiSettings.GetString("musicplayer.visualisation"); - if (strVis != "None" && strVis.size() > 4) - { // make it look pretty - strVis = strVis.Left(strVis.size() - 4); - strVis[0] = toupper(strVis[0]); - } - CStdString strSettings; - strSettings.Format(g_localizeStrings.Get(13407).c_str(), strVis.c_str()); - SET_CONTROL_LABEL(CONTROL_PRESETS_LABEL, strSettings); + + // update our dialog's label + SET_CONTROL_LABEL(CONTROL_PRESETS_LABEL, strHeading); + // if there is no presets, add a label saying so if (m_vecPresets->Size() == 0) { diff --git a/xbmc/GUIDialogVisualisationPresetList.h b/xbmc/GUIDialogVisualisationPresetList.h index b50f06c1ef..e4f594f63e 100644 --- a/xbmc/GUIDialogVisualisationPresetList.h +++ b/xbmc/GUIDialogVisualisationPresetList.h @@ -22,8 +22,11 @@ */ #include "GUIDialog.h" -#include "visualizations/Visualisation.h" +namespace ADDON +{ + class CVisualisation; +} class CFileItemList; class CGUIDialogVisualisationPresetList : @@ -36,8 +39,9 @@ public: virtual void FrameMove(); protected: - void SetVisualisation(CVisualisation *pVisualisation); - CVisualisation *m_pVisualisation; + void SetVisualisation(ADDON::CVisualisation *addon); + void Update(); + ADDON::CVisualisation* m_viz; //TODO get rid CFileItemList* m_vecPresets; - int m_currentPreset; + unsigned m_currentPreset; }; diff --git a/xbmc/GUIDialogVisualisationSettings.cpp b/xbmc/GUIDialogVisualisationSettings.cpp deleted file mode 100644 index 803b45d4d0..0000000000 --- a/xbmc/GUIDialogVisualisationSettings.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "GUIDialogVisualisationSettings.h" -#include "GUIWindowManager.h" -#include "GUIWindowSettingsCategory.h" -#include "GUISpinControlEx.h" -#include "GUIRadioButtonControl.h" -#include "GUIControlGroupList.h" -#include "GUIUserMessages.h" -#include "utils/GUIInfoManager.h" -#include "LocalizeStrings.h" - -#define CONTROL_SETTINGS_LABEL 2 -#define CONTROL_NONE_AVAILABLE 3 -#define CONTROL_GROUP_LIST 5 -#define CONTROL_DEFAULT_BUTTON 7 -#define CONTROL_DEFAULT_RADIOBUTTON 8 -#define CONTROL_DEFAULT_SPIN 9 -#define CONTROL_START 50 -#define CONTROL_PAGE 60 - -CGUIDialogVisualisationSettings::CGUIDialogVisualisationSettings(void) - : CGUIDialog(WINDOW_DIALOG_VIS_SETTINGS, "MusicOSDVisSettings.xml") -{ - m_pOriginalSpin = NULL; - m_pOriginalRadioButton = NULL; - m_pOriginalSettingsButton = NULL; - m_pVisualisation = NULL; - m_pSettings = NULL; -} - -CGUIDialogVisualisationSettings::~CGUIDialogVisualisationSettings(void) -{ -} - -bool CGUIDialogVisualisationSettings::OnMessage(CGUIMessage &message) -{ - switch (message.GetMessage()) - { - case GUI_MSG_CLICKED: - { - unsigned int iControl = message.GetSenderId(); - if (iControl >= CONTROL_START && iControl < CONTROL_PAGE) - OnClick(iControl); - return true; - } - break; - case GUI_MSG_WINDOW_DEINIT: - case GUI_MSG_VISUALISATION_UNLOADING: - { - FreeControls(); - m_pVisualisation = NULL; - m_pSettings = NULL; - } - break; - case GUI_MSG_VISUALISATION_LOADED: - { - SetVisualisation((CVisualisation *)message.GetPointer()); - SetupPage(); - SET_CONTROL_FOCUS(CONTROL_START, 0); - } - } - return CGUIDialog::OnMessage(message); -} - -void CGUIDialogVisualisationSettings::SetupPage() -{ - // cleanup first, if necessary - FreeControls(); - m_pOriginalSpin = (CGUISpinControlEx*)GetControl(CONTROL_DEFAULT_SPIN); - m_pOriginalRadioButton = (CGUIRadioButtonControl *)GetControl(CONTROL_DEFAULT_RADIOBUTTON); - m_pOriginalSettingsButton = (CGUIButtonControl *)GetControl(CONTROL_DEFAULT_BUTTON); - if (!m_pOriginalSpin || !m_pOriginalRadioButton || !m_pOriginalSettingsButton) - return; - m_pOriginalSpin->SetVisible(false); - m_pOriginalRadioButton->SetVisible(false); - m_pOriginalSettingsButton->SetVisible(false); - - // update our settings label - CStdString strSettings; - strSettings.Format("%s %s", g_infoManager.GetLabel(402).c_str(), g_localizeStrings.Get(5)); - SET_CONTROL_LABEL(CONTROL_SETTINGS_LABEL, strSettings); - - CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_GROUP_LIST); - if (!group) - return; - - if (!m_pSettings || !m_pSettings->size()) - { // no settings available - SET_CONTROL_VISIBLE(CONTROL_NONE_AVAILABLE); - return; - } - else - { - SET_CONTROL_HIDDEN(CONTROL_NONE_AVAILABLE); - } - - - // run through and create our controls - for (unsigned int i = 0; i < m_pSettings->size(); i++) - { - VisSetting &setting = m_pSettings->at(i); - AddSetting(setting, group->GetWidth(), CONTROL_START + i); - } - UpdateSettings(); -} - - -void CGUIDialogVisualisationSettings::UpdateSettings() -{ -} - -void CGUIDialogVisualisationSettings::OnClick(int iID) -{ - if (!m_pSettings || !m_pVisualisation) return; - unsigned int settingNum = iID - CONTROL_START; - if (settingNum >= m_pSettings->size()) return; - VisSetting &setting = m_pSettings->at(settingNum); - if (setting.type == VisSetting::SPIN) - { - CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(iID); - setting.current = pControl->GetValue(); - } - else if (setting.type == VisSetting::CHECK) - { - CGUIRadioButtonControl *pControl = (CGUIRadioButtonControl *)GetControl(iID); - setting.current = pControl->IsSelected() ? 1 : 0; - } - m_pVisualisation->UpdateSetting(settingNum, &m_pSettings); - UpdateSettings(); -} - -void CGUIDialogVisualisationSettings::FreeControls() -{ - // just clear our group list - CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_GROUP_LIST); - if (group) - { - group->FreeResources(); - group->ClearAll(); - } -} - -void CGUIDialogVisualisationSettings::AddSetting(VisSetting &setting, float width, int iControlID) -{ - CGUIControl *pControl = NULL; - if (setting.type == VisSetting::CHECK) - { - pControl = new CGUIRadioButtonControl(*m_pOriginalRadioButton); - if (!pControl) return ; - ((CGUIRadioButtonControl *)pControl)->SetLabel(setting.name); - pControl->SetWidth(width); - ((CGUIRadioButtonControl *)pControl)->SetSelected(setting.current == 1); - } - else if (setting.type == VisSetting::SPIN && setting.entry.size() > 0) - { - pControl = new CGUISpinControlEx(*m_pOriginalSpin); - if (!pControl) return ; - pControl->SetWidth(width); - ((CGUISpinControlEx *)pControl)->SetText(setting.name); - pControl->SetWidth(width); - for (unsigned int i = 0; i < setting.entry.size(); i++) - ((CGUISpinControlEx *)pControl)->AddLabel(setting.entry[i], i); - ((CGUISpinControlEx *)pControl)->SetValue(setting.current); - } - if (!pControl) return; - pControl->SetID(iControlID); - pControl->SetVisible(true); - CGUIControlGroupList *group = (CGUIControlGroupList *)GetControl(CONTROL_GROUP_LIST); - if (group) - { - pControl->AllocResources(); - group->AddControl(pControl); - } - else - delete pControl; -} - -void CGUIDialogVisualisationSettings::SetVisualisation(CVisualisation *pVisualisation) -{ - m_pVisualisation = pVisualisation; - if (m_pVisualisation) - { - m_pVisualisation->GetSettings(&m_pSettings); - } -} - -void CGUIDialogVisualisationSettings::OnInitWindow() -{ - // set our visualisation - CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0); - g_windowManager.SendMessage(msg); - SetVisualisation((CVisualisation *)msg.GetPointer()); - - SetupPage(); - // reset the default control - m_lastControlID = CONTROL_START; - CGUIDialog::OnInitWindow(); -} - diff --git a/xbmc/GUIDialogVisualisationSettings.h b/xbmc/GUIDialogVisualisationSettings.h deleted file mode 100644 index 1fc6bc76a1..0000000000 --- a/xbmc/GUIDialogVisualisationSettings.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "GUIDialog.h" -#include "visualizations/Visualisation.h" - -class CGUISpinControlEx; -class CGUIRadioButtonControl; -class CGUIButtonControl; - -class CGUIDialogVisualisationSettings : - public CGUIDialog -{ -public: - CGUIDialogVisualisationSettings(void); - virtual ~CGUIDialogVisualisationSettings(void); - virtual bool OnMessage(CGUIMessage &message); -protected: - virtual void OnInitWindow(); - void SetVisualisation(CVisualisation *pVisualisation); - virtual void SetupPage(); - void UpdateSettings(); - virtual void FreeControls(); - void OnClick(int iControl); - void AddSetting(VisSetting &setting, float width, int iControlID); - - CGUISpinControlEx *m_pOriginalSpin; - CGUIRadioButtonControl *m_pOriginalRadioButton; - CGUIButtonControl *m_pOriginalSettingsButton; - - CVisualisation *m_pVisualisation; - std::vector<VisSetting> *m_pSettings; -}; diff --git a/xbmc/GUIMediaWindow.cpp b/xbmc/GUIMediaWindow.cpp index 88fdf91daa..e4af255f56 100644 --- a/xbmc/GUIMediaWindow.cpp +++ b/xbmc/GUIMediaWindow.cpp @@ -23,6 +23,7 @@ #include "GUIUserMessages.h" #include "Util.h" #include "PlayListPlayer.h" +#include "utils/AddonManager.h" #include "FileSystem/ZipManager.h" #include "FileSystem/PluginDirectory.h" #include "FileSystem/MultiPathDirectory.h" @@ -40,8 +41,8 @@ #include "GUISettings.h" #include "GUIDialogSmartPlaylistEditor.h" -#include "GUIDialogPluginSettings.h" -#include "PluginSettings.h" +#include "GUIDialogAddonSettings.h" +#include "GUIDialogYesNo.h" #include "GUIWindowManager.h" #include "GUIDialogOK.h" #include "PlayList.h" @@ -64,6 +65,7 @@ #define CONTROL_LABELFILES 12 using namespace std; +using namespace ADDON; CGUIMediaWindow::CGUIMediaWindow(int id, const char *xmlFile) : CGUIWindow(id, xmlFile) @@ -1304,19 +1306,6 @@ void CGUIMediaWindow::GetContextButtons(int itemNumber, CContextButtons &buttons buttons.Add((CONTEXT_BUTTON)i, item->GetProperty(label)); } - if (item->IsPlugin() && item->m_bIsFolder) - { - if (CPluginSettings::SettingsExist(item->m_strPath)) - buttons.Add(CONTEXT_BUTTON_PLUGIN_SETTINGS, 1045); - if (m_vecItems->m_strPath.Equals("plugin://music/") || - m_vecItems->m_strPath.Equals("plugin://video/") || - m_vecItems->m_strPath.Equals("plugin://pictures/") || - m_vecItems->m_strPath.Equals("plugin://programs/") ) - { - buttons.Add(CONTEXT_BUTTON_DELETE_PLUGIN, 117); - } - } - if (item->GetPropertyBOOL("pluginreplacecontextitems")) return; @@ -1342,20 +1331,11 @@ bool CGUIMediaWindow::OnContextButton(int itemNumber, CONTEXT_BUTTON button) } case CONTEXT_BUTTON_PLUGIN_SETTINGS: { - CURL url(m_vecItems->Get(itemNumber)->m_strPath); - if(CGUIDialogPluginSettings::ShowAndGetInput(url)) - Update(m_vecItems->m_strPath); - return true; - } - case CONTEXT_BUTTON_DELETE_PLUGIN: - { - CStdString path; - CUtil::GetDirectory(m_vecItems->Get(itemNumber)->m_strPath,path); - path.Replace("plugin://","special://home/plugins/"); - CFileItemPtr item2(new CFileItem(path,true)); - if (CFileUtils::DeleteItem(item2)) - Update(m_vecItems->m_strPath); - + CURL plugin(m_vecItems->Get(itemNumber)->m_strPath); + ADDON::AddonPtr addon; + if (CAddonMgr::Get()->GetAddon(ADDON_PLUGIN, plugin.GetHostName(), addon)) + if (CGUIDialogAddonSettings::ShowAndGetInput(addon)) + Update(m_vecItems->m_strPath); return true; } case CONTEXT_BUTTON_USER1: diff --git a/xbmc/GUIPassword.cpp b/xbmc/GUIPassword.cpp index a6152045e1..e4803bfb19 100644 --- a/xbmc/GUIPassword.cpp +++ b/xbmc/GUIPassword.cpp @@ -179,7 +179,7 @@ bool CGUIPassword::SetMasterLockMode(bool bDetails) if (pDialog) { CProfile& profile=g_settings.m_vecProfiles.at(0); - if (pDialog->ShowAndGetLock(profile._iLockMode,profile._strLockCode,profile._bLockMusic,profile._bLockVideo,profile._bLockPictures,profile._bLockPrograms,profile._bLockFiles,profile._bLockSettings,12360,true,bDetails)) + if (pDialog->ShowAndGetLock(profile._iLockMode,profile._strLockCode,profile._bLockMusic,profile._bLockVideo,profile._bLockPictures,profile._bLockPrograms,profile._bLockFiles,profile._bLockSettings,profile._bLockAddonManager,12360,true,bDetails)) return true; return false; diff --git a/xbmc/GUISettings.cpp b/xbmc/GUISettings.cpp index 8695be9b76..e67a71f486 100644 --- a/xbmc/GUISettings.cpp +++ b/xbmc/GUISettings.cpp @@ -253,8 +253,7 @@ void CGUISettings::Initialize() AddString(wea, "weather.areacode2", 14020, "UKXX0085 - London, United Kingdom", BUTTON_CONTROL_STANDARD); AddString(wea, "weather.areacode3", 14021, "JAXX0085 - Tokyo, Japan", BUTTON_CONTROL_STANDARD); AddSeparator(wea, "weather.sep1"); - AddString(wea, "weather.plugin", 23000, "", SPIN_CONTROL_TEXT, true); - AddString(wea, "weather.pluginsettings", 23001, "", BUTTON_CONTROL_STANDARD, true); + AddString(wea, "weather.plugin", 24027, "", SPIN_CONTROL_TEXT, true); // My Music Settings AddGroup(3, 2); @@ -264,7 +263,6 @@ void CGUISettings::Initialize() AddSeparator(ml,"musiclibrary.sep1"); AddBool(ml,"musiclibrary.downloadinfo", 20192, false); AddString(ml, "musiclibrary.scraper", 20194, "allmusic.xml", SPIN_CONTROL_TEXT); - AddString(ml, "musiclibrary.scrapersettings", 21417, "", BUTTON_CONTROL_STANDARD); AddBool(ml, "musiclibrary.updateonstartup", 22000, false); AddBool(NULL, "musiclibrary.backgroundupdate", 22001, false); AddSeparator(ml,"musiclibrary.sep2"); @@ -1119,10 +1117,6 @@ void CGUISettings::LoadXML(TiXmlElement *pRootElement, bool hideSettings /* = fa m_replayGain.iType = GetInt("musicplayer.replaygaintype"); m_replayGain.bAvoidClipping = GetBool("musicplayer.replaygainavoidclipping"); - // check if we load the right vis - if(!CVisualisation::IsValidVisualisation(g_guiSettings.GetString("musicplayer.visualisation"))) - g_guiSettings.SetString("musicplayer.visualisation", DEFAULT_VISUALISATION); - #if defined(_LINUX) && !defined(__APPLE__) CStdString timezone = GetString("locale.timezone"); if(timezone == "0" || timezone.IsEmpty()) diff --git a/xbmc/GUIViewState.cpp b/xbmc/GUIViewState.cpp index 153b0bdad4..8ef944ef25 100644 --- a/xbmc/GUIViewState.cpp +++ b/xbmc/GUIViewState.cpp @@ -33,6 +33,7 @@ #include "ViewDatabase.h" #include "AutoSwitch.h" #include "GUIWindowManager.h" +#include "utils/AddonManager.h" #include "ViewState.h" #include "GUISettings.h" #include "Settings.h" @@ -46,6 +47,9 @@ VECSOURCES CGUIViewState::m_sources; CGUIViewState* CGUIViewState::GetViewState(int windowId, const CFileItemList& items) { + // don't expect derived classes to clear the sources + m_sources.clear(); + if (windowId == 0) return GetViewState(g_windowManager.GetActiveWindow(),items); @@ -120,11 +124,12 @@ CGUIViewState* CGUIViewState::GetViewState(int windowId, const CFileItemList& it return new CGUIViewStateGeneral(items); } -CGUIViewState::CGUIViewState(const CFileItemList& items) : m_items(items) +CGUIViewState::CGUIViewState(const CFileItemList& items, const CONTENT_TYPE& content/*=CONTENT_NONE*/) : m_items(items) { m_currentViewAsControl=0; m_currentSortMethod=0; m_sortOrder=SORT_ORDER_ASC; + m_content = content; } CGUIViewState::~CGUIViewState() @@ -332,6 +337,29 @@ CStdString CGUIViewState::GetExtensions() VECSOURCES& CGUIViewState::GetSources() { + // more consolidation could happen here for all content types + // - playlists, autoconfig network shares, whatnot + + if (m_content == CONTENT_NONE) + return m_sources; + + ADDON::VECADDONS addons; + ADDON::CAddonMgr::Get()->GetAddons(ADDON::ADDON_PLUGIN, addons, m_content); + + for (unsigned i=0; i<addons.size(); i++) + { + // format for sources's path is + // eg. pictures://UUID + CMediaSource plugin; + CURL path; + path.SetProtocol(ADDON::TranslateContent(m_content)); + path.SetHostName(addons[i]->UUID()); + plugin.strPath = path.Get(); + plugin.strName = addons[i]->Name(); + plugin.m_strThumbnailImage = addons[i]->Icon(); //FIXME cache by UUID + plugin.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOTE; + m_sources.push_back(plugin); + } return m_sources; } diff --git a/xbmc/GUIViewState.h b/xbmc/GUIViewState.h index de5e431775..cb910bc505 100644 --- a/xbmc/GUIViewState.h +++ b/xbmc/GUIViewState.h @@ -25,6 +25,7 @@ #include "SortFileItem.h" #include "GUIBaseContainer.h" #include "MediaSource.h" +#include "utils/IAddon.h" class CViewState; // forward class CFileItemList; @@ -62,7 +63,7 @@ public: virtual VECSOURCES& GetSources(); protected: - CGUIViewState(const CFileItemList& items); // no direct object creation, use GetViewState() + CGUIViewState(const CFileItemList& items, const CONTENT_TYPE& content = CONTENT_NONE); // no direct object creation, use GetViewState() virtual void SaveViewState()=0; virtual void SaveViewToDb(const CStdString &path, int windowID, CViewState *viewState = NULL); void LoadViewState(const CStdString &path, int windowID); @@ -73,6 +74,7 @@ protected: const CFileItemList& m_items; static VECSOURCES m_sources; + CONTENT_TYPE m_content; int m_currentViewAsControl; diff --git a/xbmc/GUIViewStateMusic.cpp b/xbmc/GUIViewStateMusic.cpp index 61b1403385..cad44107a3 100644 --- a/xbmc/GUIViewStateMusic.cpp +++ b/xbmc/GUIViewStateMusic.cpp @@ -32,9 +32,9 @@ #include "LocalizeStrings.h" #include "utils/log.h" +#include "FileSystem/Directory.h" #include "FileSystem/MusicDatabaseDirectory.h" #include "FileSystem/VideoDatabaseDirectory.h" -#include "FileSystem/PluginDirectory.h" #include "FileSystem/ShoutcastDirectory.h" using namespace XFILE; @@ -567,16 +567,6 @@ VECSOURCES& CGUIViewStateWindowMusicNav::GetSources() m_sources.push_back(share); } - // plugins share - if (CPluginDirectory::HasPlugins("music") && g_advancedSettings.m_bVirtualShares) - { - share.strName = g_localizeStrings.Get(1038); - share.strPath = "plugin://music/"; - share.m_strThumbnailImage = CUtil::GetDefaultFolderThumb("DefaultMusicPlugins.png"); - share.m_ignore = true; - m_sources.push_back(share); - } - return CGUIViewStateWindowMusic::GetSources(); } @@ -623,14 +613,7 @@ void CGUIViewStateWindowMusicSongs::SaveViewState() VECSOURCES& CGUIViewStateWindowMusicSongs::GetSources() { - // plugins share - if (CPluginDirectory::HasPlugins("music") && g_advancedSettings.m_bVirtualShares) - { - CMediaSource share; - share.strName = g_localizeStrings.Get(1038); - share.strPath = "plugin://music/"; - AddOrReplace(g_settings.m_musicSources,share); - } + AddOrReplace(g_settings.m_musicSources, CGUIViewState::GetSources()); return g_settings.m_musicSources; } @@ -682,7 +665,8 @@ VECSOURCES& CGUIViewStateWindowMusicPlaylist::GetSources() share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; m_sources.push_back(share); - return CGUIViewStateWindowMusic::GetSources(); + // CGUIViewState::GetSources would add music plugins + return m_sources; } CGUIViewStateMusicShoutcast::CGUIViewStateMusicShoutcast(const CFileItemList& items) : CGUIViewStateWindowMusic(items) diff --git a/xbmc/GUIViewStateMusic.h b/xbmc/GUIViewStateMusic.h index 1265389e81..086bef37ef 100644 --- a/xbmc/GUIViewStateMusic.h +++ b/xbmc/GUIViewStateMusic.h @@ -27,7 +27,7 @@ class CGUIViewStateWindowMusic : public CGUIViewState { public: - CGUIViewStateWindowMusic(const CFileItemList& items) : CGUIViewState(items) {} + CGUIViewStateWindowMusic(const CFileItemList& items) : CGUIViewState(items, CONTENT_ALBUMS) {} protected: virtual int GetPlaylist(); virtual bool AutoPlayNextItem(); diff --git a/xbmc/GUIViewStatePictures.cpp b/xbmc/GUIViewStatePictures.cpp index 4155f02708..05534f57e9 100644 --- a/xbmc/GUIViewStatePictures.cpp +++ b/xbmc/GUIViewStatePictures.cpp @@ -34,7 +34,7 @@ using namespace XFILE; -CGUIViewStateWindowPictures::CGUIViewStateWindowPictures(const CFileItemList& items) : CGUIViewState(items) +CGUIViewStateWindowPictures::CGUIViewStateWindowPictures(const CFileItemList& items) : CGUIViewState(items, CONTENT_PICTURES) { if (items.IsVirtualDirectoryRoot()) { @@ -80,16 +80,7 @@ CStdString CGUIViewStateWindowPictures::GetExtensions() VECSOURCES& CGUIViewStateWindowPictures::GetSources() { - // plugins share - if (CPluginDirectory::HasPlugins("pictures") && g_advancedSettings.m_bVirtualShares) - { - CMediaSource share; - share.strName = g_localizeStrings.Get(1039); // Picture Plugins - share.strPath = "plugin://pictures/"; - share.m_strThumbnailImage = CUtil::GetDefaultFolderThumb("DefaultPicturePlugins.png"); - share.m_ignore = true; - AddOrReplace(g_settings.m_pictureSources,share); - } + AddOrReplace(g_settings.m_pictureSources, CGUIViewState::GetSources()); return g_settings.m_pictureSources; } diff --git a/xbmc/GUIViewStatePrograms.cpp b/xbmc/GUIViewStatePrograms.cpp index 60e9a5512f..ea216ef2e6 100644 --- a/xbmc/GUIViewStatePrograms.cpp +++ b/xbmc/GUIViewStatePrograms.cpp @@ -33,7 +33,7 @@ using namespace XFILE; -CGUIViewStateWindowPrograms::CGUIViewStateWindowPrograms(const CFileItemList& items) : CGUIViewState(items) +CGUIViewStateWindowPrograms::CGUIViewStateWindowPrograms(const CFileItemList& items) : CGUIViewState(items, CONTENT_PROGRAMS) { if (g_guiSettings.GetBool("filelists.ignorethewhensorting")) AddSortMethod(SORT_METHOD_LABEL_IGNORE_THE, 551, LABEL_MASKS("%K", "%I", "%L", "")); // Titel, Size | Foldername, empty @@ -68,16 +68,7 @@ CStdString CGUIViewStateWindowPrograms::GetExtensions() VECSOURCES& CGUIViewStateWindowPrograms::GetSources() { - // plugins share - if (CPluginDirectory::HasPlugins("programs")) - { - CMediaSource share; - share.strName = g_localizeStrings.Get(1043); // Program Plugins - share.strPath = "plugin://programs/"; - share.m_strThumbnailImage = CUtil::GetDefaultFolderThumb("DefaultProgramPlugins.png"); - share.m_ignore= true; - AddOrReplace(g_settings.m_programSources,share); - } + AddOrReplace(g_settings.m_programSources,CGUIViewState::GetSources()); return g_settings.m_programSources; } diff --git a/xbmc/GUIViewStateScripts.cpp b/xbmc/GUIViewStateScripts.cpp index 98dc7aee3e..50ba399b6a 100644 --- a/xbmc/GUIViewStateScripts.cpp +++ b/xbmc/GUIViewStateScripts.cpp @@ -62,24 +62,7 @@ VECSOURCES& CGUIViewStateWindowScripts::GetSources() m_sources.clear(); CMediaSource share; - if (g_settings.m_vecProfiles.size() > 1) - { - if (CDirectory::Exists("special://profile/scripts")) - { - CMediaSource share2; - share2.strName = "Profile Scripts"; - share2.strPath = "special://profile/scripts"; - share2.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; - m_sources.push_back(share2); - } - share.strName = "Shared Scripts"; - } - else - share.strName = "Scripts"; - - share.strPath = "special://home/scripts"; - if (!CDirectory::Exists(share.strPath)) - share.strPath = "special://xbmc/scripts"; + share.strPath = "special://xbmc/scripts"; share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; m_sources.push_back(share); diff --git a/xbmc/GUIViewStateVideo.cpp b/xbmc/GUIViewStateVideo.cpp index b68087d4fc..d1d39e0946 100644 --- a/xbmc/GUIViewStateVideo.cpp +++ b/xbmc/GUIViewStateVideo.cpp @@ -87,15 +87,7 @@ void CGUIViewStateWindowVideoFiles::SaveViewState() VECSOURCES& CGUIViewStateWindowVideoFiles::GetSources() { - // plugins share - if (CPluginDirectory::HasPlugins("video") && g_advancedSettings.m_bVirtualShares) - { - CMediaSource share; - share.strName = g_localizeStrings.Get(1037); - share.strPath = "plugin://video/"; - share.m_ignore = true; - AddOrReplace(g_settings.m_videoSources,share); - } + AddOrReplace(g_settings.m_videoSources, CGUIViewState::GetSources()); return g_settings.m_videoSources; } @@ -395,15 +387,6 @@ VECSOURCES& CGUIViewStateWindowVideoNav::GetSources() share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; m_sources.push_back(share); - // plugins share - if (CPluginDirectory::HasPlugins("video") && g_advancedSettings.m_bVirtualShares) - { - share.strName = g_localizeStrings.Get(1037); - share.strPath = "plugin://video/"; - share.m_strThumbnailImage = CUtil::GetDefaultFolderThumb("DefaultVideoPlugins.png"); - m_sources.push_back(share); - } - return CGUIViewStateWindowVideo::GetSources(); } @@ -453,7 +436,8 @@ VECSOURCES& CGUIViewStateWindowVideoPlaylist::GetSources() share.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL; m_sources.push_back(share); - return CGUIViewStateWindowVideo::GetSources(); + // no plugins in playlist window + return m_sources; } diff --git a/xbmc/GUIViewStateVideo.h b/xbmc/GUIViewStateVideo.h index c1d339716f..e1f4d76b9a 100644 --- a/xbmc/GUIViewStateVideo.h +++ b/xbmc/GUIViewStateVideo.h @@ -27,7 +27,7 @@ class CGUIViewStateWindowVideo : public CGUIViewState { public: - CGUIViewStateWindowVideo(const CFileItemList& items) : CGUIViewState(items) {} + CGUIViewStateWindowVideo(const CFileItemList& items) : CGUIViewState(items, CONTENT_MOVIES) {} protected: virtual CStdString GetLockType(); diff --git a/xbmc/GUIWindowAddonBrowser.cpp b/xbmc/GUIWindowAddonBrowser.cpp new file mode 100644 index 0000000000..5deb3ee963 --- /dev/null +++ b/xbmc/GUIWindowAddonBrowser.cpp @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2005-2010 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "utils/AddonManager.h" +#include "GUIWindowAddonBrowser.h" +#include "GUISpinControlEx.h" +#include "Settings.h" +#include "GUIDialogContextMenu.h" +#include "GUIDialogAddonSettings.h" +#include "GUIDialogYesNo.h" +#include "GUIDialogNumeric.h" +#include "GUIDialogKeyboard.h" +#include "GUIWindowManager.h" +#include "Util.h" +#include "URL.h" +#include "utils/log.h" +#include "FileItem.h" + +#define CONTROL_ADDONSLIST 2 +#define CONTROL_HEADING_LABEL 411 + +using namespace ADDON; + +CGUIWindowAddonBrowser::CGUIWindowAddonBrowser(void) +: CGUIWindow(WINDOW_ADDON_BROWSER, "AddonBrowser.xml") +{ + m_vecItems = new CFileItemList; +} + +CGUIWindowAddonBrowser::~CGUIWindowAddonBrowser() +{ +} + +bool CGUIWindowAddonBrowser::OnAction(const CAction &action) +{ + if (action.GetID() == ACTION_PREVIOUS_MENU) + { + g_windowManager.PreviousWindow(); + return true; + } + else if (action.GetID() == ACTION_CONTEXT_MENU || action.GetID() == ACTION_MOUSE_RIGHT_CLICK) + { + int iItem = GetSelectedItem(); + return OnContextMenu(iItem); + } + return CGUIWindow::OnAction(action); +} + +bool CGUIWindowAddonBrowser::OnMessage(CGUIMessage& message) +{ + switch ( message.GetMessage() ) + { + case GUI_MSG_WINDOW_DEINIT: + { + CGUIWindow::OnMessage(message); + ClearListItems(); + return true; + } + break; + + case GUI_MSG_CLICKED: + { + if (message.GetSenderId() == CONTROL_ADDONSLIST) // list control + { + int iItem = GetSelectedItem(); + int iAction = message.GetParam1(); + if (iItem < 0) break; + if (iAction == ACTION_SELECT_ITEM || iAction == ACTION_MOUSE_LEFT_CLICK) + { + OnClick(iItem); + return true; + } + if (iAction == ACTION_CONTEXT_MENU || iAction == ACTION_MOUSE_RIGHT_CLICK) + { + return OnContextMenu(iItem); + } + } + } + break; + } + return CGUIWindow::OnMessage(message); +} + +void CGUIWindowAddonBrowser::ClearListItems() +{ + m_vecItems->Clear(); +} + +void CGUIWindowAddonBrowser::OnInitWindow() +{ + Update(); + CGUIWindow::OnInitWindow(); +} + +int CGUIWindowAddonBrowser::GetSelectedItem() +{ + CGUIMessage msg(GUI_MSG_ITEM_SELECTED, GetID(), CONTROL_ADDONSLIST); + g_windowManager.SendMessage(msg); + + return msg.GetParam1(); +} + +bool CGUIWindowAddonBrowser::SelectItem(int select) +{ + CGUIMessage msg(GUI_MSG_ITEM_SELECT, GetID(), CONTROL_ADDONSLIST, select); + return g_windowManager.SendMessage(msg); +} + +void CGUIWindowAddonBrowser::OnSort() +{ + m_vecItems->Sort(SORT_METHOD_LABEL, SORT_ORDER_ASC); +} + +void CGUIWindowAddonBrowser::Update() +{ + int selected = GetSelectedItem(); + m_vecItems->Clear(); + + VECADDONS addons; + CAddonMgr::Get()->GetAllAddons(addons, false); + + for (unsigned i=0; i < addons.size(); i++) + { + AddonPtr addon = addons[i]; + CFileItemPtr pItem(new CFileItem(addon->UUID(), false)); + pItem->SetLabel(addon->Name()); + pItem->SetProperty("Addon.UUID", addon->UUID()); + pItem->SetProperty("Addon.Type", TranslateType(addon->Type())); + pItem->SetProperty("Addon.Disabled", addon->Disabled()); + pItem->SetProperty("Addon.Name", addon->Name()); + pItem->SetProperty("Addon.Version", addon->Version().Print()); + pItem->SetProperty("Addon.Summary", addon->Summary()); + pItem->SetProperty("Addon.Description", addon->Description()); + pItem->SetProperty("Addon.Creator", addon->Author()); + pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer()); + pItem->SetProperty("Addon.Rating", addon->Stars()); + pItem->SetThumbnailImage(addon->Icon()); + m_vecItems->Add(pItem); + } + + OnSort(); + CGUIMessage msg(GUI_MSG_LABEL_BIND, GetID(), CONTROL_ADDONSLIST, 0, 0, m_vecItems); + OnMessage(msg); + + if (selected != 0) + SelectItem(selected); +} + +void CGUIWindowAddonBrowser::OnClick(int iItem) +{ + if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return ; + CFileItemPtr pItem = (*m_vecItems)[iItem]; + CStdString strPath = pItem->m_strPath; + + // check if user is allowed to open this window + if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].addonmanagerLocked() && g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE) + if (!g_passwordManager.IsMasterLockUnlocked(true)) + return; + + AddonPtr addon; + TYPE type = TranslateType(pItem->GetProperty("Addon.Type")); + if (CAddonMgr::Get()->GetAddon(type, pItem->GetProperty("Addon.UUID"), addon)) + { + if (addon->Disabled()) + { + CAddonMgr::Get()->EnableAddon(addon); + Update(); + + } + else + CGUIDialogAddonSettings::ShowAndGetInput(addon); + } +} + +bool CGUIWindowAddonBrowser::OnContextMenu(int iItem) +{ + // check if user is allowed to open this window + if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].addonmanagerLocked() && g_settings.m_vecProfiles[0].getLockMode() != LOCK_MODE_EVERYONE) + if (!g_passwordManager.IsMasterLockUnlocked(true)) + return false; + + CGUIDialogContextMenu* pMenu = (CGUIDialogContextMenu*)g_windowManager.GetWindow(WINDOW_DIALOG_CONTEXT_MENU); + if (!pMenu) + return false; + + pMenu->Initialize(); + CFileItemPtr pItem = m_vecItems->Get(iItem); + + TYPE type = TranslateType(pItem->GetProperty("Addon.Type")); + AddonPtr addon; + if (!CAddonMgr::Get()->GetAddon(type, pItem->GetProperty("Addon.UUID"), addon)) + return false; + + int iSettingsLabel = 24020; + int iDisableLabel = 24021; + int iEnableLabel = 24022; + + int btn_Disable = -1; + int btn_Enable = -1; + int btn_Settings = -1; + + if (addon->Disabled()) + btn_Enable = pMenu->AddButton(iEnableLabel); + else + { + btn_Disable = pMenu->AddButton(iDisableLabel); + btn_Settings = pMenu->AddButton(iSettingsLabel); + } + + pMenu->CenterWindow(); + pMenu->DoModal(); + + int btnid = pMenu->GetButton(); + if (btnid == -1) + return false; + + if (btnid == btn_Settings) + { + CGUIDialogAddonSettings::ShowAndGetInput(addon); + return true; + } + else if (btnid == btn_Disable) + { + CAddonMgr::Get()->DisableAddon(addon); + Update(); + return true; + } + else if (btnid == btn_Enable) + { + CAddonMgr::Get()->EnableAddon(addon); + Update(); + return true; + } + return false; +} + diff --git a/xbmc/visualizations/VisualisationFactory.h b/xbmc/GUIWindowAddonBrowser.h index 36c16b8efb..47396ef270 100644 --- a/xbmc/visualizations/VisualisationFactory.h +++ b/xbmc/GUIWindowAddonBrowser.h @@ -1,6 +1,7 @@ #pragma once + /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2010 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -19,13 +20,33 @@ * http://www.gnu.org/copyleft/gpl.html * */ -#include "Visualisation.h" -class CVisualisationFactory +#include "Addon.h" +#include "GUIWindow.h" +#include "GUIViewControl.h" + +class CFileItem; +class CFileItemList; + +class CGUIWindowAddonBrowser : + public CGUIWindow { public: - CVisualisationFactory(); - virtual ~CVisualisationFactory(); - CVisualisation* LoadVisualisation(const CStdString& strVisz) const; - CVisualisation* LoadVisualisation(const CStdString& strVisz, const CStdString& strSubModule) const; + CGUIWindowAddonBrowser(void); + virtual ~CGUIWindowAddonBrowser(void); + virtual bool OnMessage(CGUIMessage& message); + virtual bool OnAction(const CAction &action); + +protected: + virtual void OnInitWindow(); + int GetSelectedItem(); + bool SelectItem(int select); + void OnClick(int iItem); + void OnSort(); + void ClearListItems(); + void Update(); + bool OnContextMenu(int iItem); + + CFileItemList* m_vecItems; }; + diff --git a/xbmc/GUIWindowMusicBase.cpp b/xbmc/GUIWindowMusicBase.cpp index b67f4bbe30..c97a96779e 100644 --- a/xbmc/GUIWindowMusicBase.cpp +++ b/xbmc/GUIWindowMusicBase.cpp @@ -431,13 +431,8 @@ void CGUIWindowMusicBase::ShowArtistInfo(const CArtist& artist, const CStdString return; } - // find album info - SScraperInfo scraper; - if (!m_musicdatabase.GetScraperForPath(path,scraper)) - return; - CMusicArtistInfo info; - if (FindArtistInfo(artist.strArtist, info, scraper, bShowInfo ? (bRefresh ? SELECTION_FORCED : SELECTION_ALLOWED) : SELECTION_AUTO)) + if (FindArtistInfo(artist.strArtist, info, bShowInfo ? (bRefresh ? SELECTION_FORCED : SELECTION_ALLOWED) : SELECTION_AUTO)) { // download the album info if ( info.Loaded() ) @@ -529,13 +524,8 @@ void CGUIWindowMusicBase::ShowAlbumInfo(const CAlbum& album, const CStdString& p return; } - // find album info - SScraperInfo scraper; - if (!m_musicdatabase.GetScraperForPath(path,scraper)) - return; - CMusicAlbumInfo info; - if (FindAlbumInfo(album.strAlbum, album.strArtist, info, scraper, bShowInfo ? (bRefresh ? SELECTION_FORCED : SELECTION_ALLOWED) : SELECTION_AUTO)) + if (FindAlbumInfo(album.strAlbum, album.strArtist, info, bShowInfo ? (bRefresh ? SELECTION_FORCED : SELECTION_ALLOWED) : SELECTION_AUTO)) { // download the album info if ( info.Loaded() ) @@ -779,7 +769,7 @@ void CGUIWindowMusicBase::UpdateButtons() CGUIMediaWindow::UpdateButtons(); } -bool CGUIWindowMusicBase::FindAlbumInfo(const CStdString& strAlbum, const CStdString& strArtist, CMusicAlbumInfo& album, const SScraperInfo& info, ALLOW_SELECTION allowSelection) +bool CGUIWindowMusicBase::FindAlbumInfo(const CStdString& strAlbum, const CStdString& strArtist, CMusicAlbumInfo& album, ALLOW_SELECTION allowSelection) { // show dialog box indicating we're searching the album if (m_dlgProgress && allowSelection != SELECTION_AUTO) @@ -830,7 +820,7 @@ bool CGUIWindowMusicBase::FindAlbumInfo(const CStdString& strAlbum, const CStdSt return true; } -bool CGUIWindowMusicBase::FindArtistInfo(const CStdString& strArtist, CMusicArtistInfo& artist, const SScraperInfo& info, ALLOW_SELECTION allowSelection) +bool CGUIWindowMusicBase::FindArtistInfo(const CStdString& strArtist, CMusicArtistInfo& artist, ALLOW_SELECTION allowSelection) { // show dialog box indicating we're searching the album if (m_dlgProgress && allowSelection != SELECTION_AUTO) diff --git a/xbmc/GUIWindowMusicBase.h b/xbmc/GUIWindowMusicBase.h index dea204ce79..928dd2caf1 100644 --- a/xbmc/GUIWindowMusicBase.h +++ b/xbmc/GUIWindowMusicBase.h @@ -33,8 +33,6 @@ #include "PlayListPlayer.h" #include "MusicInfoLoader.h" -struct SScraperInfo; - /*! \ingroup windows \brief The base class for music windows @@ -82,8 +80,8 @@ protected: void OnInfoAll(int iItem, bool bCurrent=false); virtual void OnQueueItem(int iItem); enum ALLOW_SELECTION { SELECTION_ALLOWED = 0, SELECTION_AUTO, SELECTION_FORCED }; - bool FindAlbumInfo(const CStdString& strAlbum, const CStdString& strArtist, MUSIC_GRABBER::CMusicAlbumInfo& album, const SScraperInfo& info, ALLOW_SELECTION allowSelection); - bool FindArtistInfo(const CStdString& strArtist, MUSIC_GRABBER::CMusicArtistInfo& artist, const SScraperInfo& info, ALLOW_SELECTION allowSelection); + bool FindAlbumInfo(const CStdString& strAlbum, const CStdString& strArtist, MUSIC_GRABBER::CMusicAlbumInfo& album, ALLOW_SELECTION allowSelection); + bool FindArtistInfo(const CStdString& strArtist, MUSIC_GRABBER::CMusicArtistInfo& artist, ALLOW_SELECTION allowSelection); void ShowAlbumInfo(const CAlbum &album, const CStdString &strPath, bool bRefresh, bool bShowInfo = true); void ShowArtistInfo(const CArtist &artist, const CStdString &strPath, bool bRefresh, bool bShowInfo = true); diff --git a/xbmc/GUIWindowMusicNav.cpp b/xbmc/GUIWindowMusicNav.cpp index bc76e8ae66..cb2a2aecd6 100644 --- a/xbmc/GUIWindowMusicNav.cpp +++ b/xbmc/GUIWindowMusicNav.cpp @@ -492,8 +492,8 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt m_vecItems->m_strPath.Equals("special://musicplaylists/"); CMusicDatabaseDirectory dir; - SScraperInfo info; - m_musicdatabase.GetScraperForPath(item->m_strPath,info); + ADDON::ScraperPtr info; + m_musicdatabase.GetScraperForPath(item->m_strPath, info); // enable music info button on an album or on a song. if (item->IsAudio() && !item->IsPlayList() && !item->IsSmartPlayList() && !item->IsLastFM() && !item->IsShoutCast() && !item->m_bIsFolder) @@ -536,7 +536,7 @@ void CGUIWindowMusicNav::GetContextButtons(int itemNumber, CContextButtons &butt // enable query all artist button only in album view if (dir.IsArtistDir(item->m_strPath) && !dir.IsAllItem(item->m_strPath) && - item->m_bIsFolder && !item->IsVideoDb() && !info.strContent.IsEmpty()) + item->m_bIsFolder && !item->IsVideoDb() && info->Supports(CONTENT_ALBUMS)) { buttons.Add(CONTEXT_BUTTON_INFO_ALL, 21884); } @@ -640,7 +640,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) CGUIWindowVideoNav* pWindow = (CGUIWindowVideoNav*)g_windowManager.GetWindow(WINDOW_VIDEO_NAV); if (pWindow) { - SScraperInfo info; + ADDON::ScraperPtr info; pWindow->OnInfo(item.get(),info); Update(m_vecItems->m_strPath); } @@ -728,7 +728,7 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) case CONTEXT_BUTTON_SET_CONTENT: { bool bScan=false; - SScraperInfo info; + ADDON::ScraperPtr scraper; CStdString path(item->m_strPath); CQueryParams params; CDirectoryNode::GetDatabaseInfo(item->m_strPath, params); @@ -737,19 +737,24 @@ bool CGUIWindowMusicNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) else if (params.GetArtistId() != -1) path.Format("musicdb://2/%i/",params.GetArtistId()); - if (!m_musicdatabase.GetScraperForPath(path,info)) - info.strContent = "albums"; + if (!m_musicdatabase.GetScraperForPath(path,scraper)) + { + ADDON::AddonPtr defaultScraper; + if (ADDON::CAddonMgr::Get()->GetDefault(ADDON::ADDON_SCRAPER, defaultScraper, CONTENT_ALBUMS)) + { + scraper = boost::dynamic_pointer_cast<ADDON::CScraper>(defaultScraper->Clone(defaultScraper)); + } + } - int iLabel=132; - // per genre or for all artists + CONTENT_TYPE context = CONTENT_ALBUMS; if (m_vecItems->m_strPath.Left(12).Equals("musicdb://1/") || item->m_strPath.Left(12).Equals("musicdb://2/")) { - iLabel = 133; + context = CONTENT_ARTISTS; } - if (CGUIDialogContentSettings::Show(info, bScan,iLabel)) + if (CGUIDialogContentSettings::Show(scraper, bScan, context)) { - m_musicdatabase.SetScraperForPath(path,info); + m_musicdatabase.SetScraperForPath(path,scraper); if (bScan) OnInfoAll(itemNumber,true); } diff --git a/xbmc/GUIWindowScreensaver.cpp b/xbmc/GUIWindowScreensaver.cpp index 1f7c369320..023eeeb927 100644 --- a/xbmc/GUIWindowScreensaver.cpp +++ b/xbmc/GUIWindowScreensaver.cpp @@ -21,9 +21,7 @@ #include "system.h" #include "GUIWindowScreensaver.h" -#ifdef HAS_SCREENSAVER -#include "screensavers/ScreenSaverFactory.h" -#endif +#include "utils/AddonManager.h" #include "Application.h" #include "GUIPassword.h" #include "GUISettings.h" @@ -36,6 +34,7 @@ CGUIWindowScreensaver::CGUIWindowScreensaver(void) { #ifdef HAS_SCREENSAVER m_pScreenSaver = NULL; + m_addon.reset(); #endif } @@ -62,7 +61,7 @@ void CGUIWindowScreensaver::Render() } catch (...) { - OutputDebugString("Screensaver Render - ohoh!\n"); + CLog::Log(LOGERROR, "SCREENSAVER: - Exception in Render() - %s", m_addon->Name().c_str()); } return ; } @@ -75,7 +74,7 @@ void CGUIWindowScreensaver::Render() } catch (...) { - OutputDebugString("Screensaver Start - ohoh!\n"); + CLog::Log(LOGERROR, "SCREENSAVER: - Exception in Start() - %s", m_addon->Name().c_str()); } return ; } @@ -107,10 +106,8 @@ bool CGUIWindowScreensaver::OnMessage(CGUIMessage& message) #ifdef HAS_SCREENSAVER if (m_pScreenSaver) { - OutputDebugString("ScreenSaver::Stop()\n"); + CLog::Log(LOGDEBUG, "SCREENSAVER: - Stopping - %s", m_addon->Name().c_str()); m_pScreenSaver->Stop(); - - OutputDebugString("delete ScreenSaver()\n"); delete m_pScreenSaver; g_graphicsContext.ApplyStateBlock(); @@ -140,20 +137,23 @@ bool CGUIWindowScreensaver::OnMessage(CGUIMessage& message) delete m_pScreenSaver; g_graphicsContext.ApplyStateBlock(); } - m_pScreenSaver = NULL; m_bInitialized = false; + m_addon.reset(); // Setup new screensaver instance - CScreenSaverFactory factory; - CStdString strScr; - OutputDebugString("Load Screensaver\n"); - strScr.Format("special://xbmc/screensavers/%s", g_guiSettings.GetString("screensaver.mode").c_str()); - m_pScreenSaver = factory.LoadScreenSaver(strScr.c_str()); + ADDON::AddonPtr addon; + if (!ADDON::CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCREENSAVER, g_guiSettings.GetString("screensaver.mode"), addon)) + return false; + m_addon = boost::dynamic_pointer_cast<CScreenSaver>(addon); + + if (!m_addon) + return false; + + m_pScreenSaver = NULL; //TODO addonmanager loader /*factory.LoadScreenSaver(m_addon);*/ if (m_pScreenSaver) { - OutputDebugString("ScreenSaver::Create()\n"); g_graphicsContext.CaptureStateBlock(); - m_pScreenSaver->Create(); + m_addon->Create(); } #endif // setup a z-buffer diff --git a/xbmc/GUIWindowScreensaver.h b/xbmc/GUIWindowScreensaver.h index 8f983db272..5a776e3c16 100644 --- a/xbmc/GUIWindowScreensaver.h +++ b/xbmc/GUIWindowScreensaver.h @@ -51,4 +51,5 @@ private: #endif bool m_bInitialized; CCriticalSection m_critSection; + boost::shared_ptr<CScreenSaver> m_addon; }; diff --git a/xbmc/GUIWindowScripts.cpp b/xbmc/GUIWindowScripts.cpp index 41bb77801c..77a6062640 100644 --- a/xbmc/GUIWindowScripts.cpp +++ b/xbmc/GUIWindowScripts.cpp @@ -29,8 +29,8 @@ #include "GUIWindowManager.h" #include "FileSystem/File.h" #include "FileItem.h" -#include "ScriptSettings.h" -#include "GUIDialogPluginSettings.h" +#include "utils/AddonManager.h" +#include "GUIDialogAddonSettings.h" #include "Settings.h" #include "LocalizeStrings.h" #if defined(__APPLE__) @@ -74,7 +74,7 @@ bool CGUIWindowScripts::OnMessage(CGUIMessage& message) case GUI_MSG_WINDOW_INIT: { if (m_vecItems->m_strPath == "?") - m_vecItems->m_strPath = g_settings.GetScriptsFolder(); + m_vecItems->m_strPath = "special://scripts/"; return CGUIMediaWindow::OnMessage(message); } break; @@ -245,8 +245,14 @@ void CGUIWindowScripts::GetContextButtons(int itemNumber, CContextButtons &butto { CStdString path, filename; CUtil::Split(item->m_strPath, path, filename); - if (CScriptSettings::SettingsExist(path)) - buttons.Add(CONTEXT_BUTTON_SCRIPT_SETTINGS, 1049); + ADDON::AddonPtr script; + if (ADDON::CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRIPT, item->m_strPath, script)) + { + if (script->HasSettings()) + { + buttons.Add(CONTEXT_BUTTON_SCRIPT_SETTINGS, 1049); + } + } } buttons.Add(CONTEXT_BUTTON_INFO, 654); @@ -264,8 +270,12 @@ bool CGUIWindowScripts::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { CStdString path, filename; CUtil::Split(m_vecItems->Get(itemNumber)->m_strPath, path, filename); - if(CGUIDialogPluginSettings::ShowAndGetInput(path)) - Update(m_vecItems->m_strPath); + ADDON::AddonPtr script; + if (ADDON::CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRIPT, m_vecItems->Get(itemNumber)->m_strPath, script)) + { + if (CGUIDialogAddonSettings::ShowAndGetInput(script)) + Update(m_vecItems->m_strPath); + } return true; } else if (button == CONTEXT_BUTTON_DELETE) diff --git a/xbmc/GUIWindowSettingsCategory.cpp b/xbmc/GUIWindowSettingsCategory.cpp index 9be0de8509..40ecab546c 100644 --- a/xbmc/GUIWindowSettingsCategory.cpp +++ b/xbmc/GUIWindowSettingsCategory.cpp @@ -39,7 +39,6 @@ #ifdef HAS_LCD #include "utils/LCDFactory.h" #endif -#include "visualizations/VisualisationFactory.h" #include "PlayListPlayer.h" #include "SkinInfo.h" #include "GUIAudioManager.h" @@ -51,11 +50,14 @@ #include "GUIDialogGamepad.h" #include "GUIDialogNumeric.h" #include "GUIDialogFileBrowser.h" +#include "GUIDialogAddonSettings.h" #include "GUIDialogContextMenu.h" #include "GUIDialogKeyboard.h" #include "GUIDialogYesNo.h" #include "GUIDialogOK.h" #include "GUIWindowPrograms.h" +#include "visualizations/Visualisation.h" +#include "AddonManager.h" #include "MediaManager.h" #include "utils/Network.h" #include "GUIControlGroupList.h" @@ -92,9 +94,6 @@ #include "cores/AudioRenderers/AudioRendererFactory.h" #endif #include <map> -#include "ScraperSettings.h" -#include "ScriptSettings.h" -#include "GUIDialogPluginSettings.h" #include "Settings.h" #include "AdvancedSettings.h" #include "MouseStat.h" @@ -109,6 +108,7 @@ using namespace std; using namespace XFILE; +using namespace ADDON; #define CONTROL_GROUP_BUTTONS 0 #define CONTROL_GROUP_SETTINGS 1 @@ -441,22 +441,22 @@ void CGUIWindowSettingsCategory::CreateSettings() else if (strSetting.Equals("musiclibrary.scraper")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(GetSetting(pSetting->GetSetting())->GetID()); - FillInScrapers(pControl, g_guiSettings.GetString("musiclibrary.scraper"), "music"); + FillInScrapers(pControl, g_guiSettings.GetString("musiclibrary.scraper"), CONTENT_ALBUMS); } else if (strSetting.Equals("scrapers.moviedefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(GetSetting(pSetting->GetSetting())->GetID()); - FillInScrapers(pControl, g_guiSettings.GetString("scrapers.moviedefault"), "movies"); + FillInScrapers(pControl, g_guiSettings.GetString("scrapers.moviedefault"), CONTENT_MOVIES); } else if (strSetting.Equals("scrapers.tvshowdefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(GetSetting(pSetting->GetSetting())->GetID()); - FillInScrapers(pControl, g_guiSettings.GetString("scrapers.tvshowdefault"), "tvshows"); + FillInScrapers(pControl, g_guiSettings.GetString("scrapers.tvshowdefault"), CONTENT_TVSHOWS); } else if (strSetting.Equals("scrapers.musicvideodefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(GetSetting(pSetting->GetSetting())->GetID()); - FillInScrapers(pControl, g_guiSettings.GetString("scrapers.musicvideodefault"), "musicvideos"); + FillInScrapers(pControl, g_guiSettings.GetString("scrapers.musicvideodefault"), CONTENT_MUSICVIDEOS); } else if (strSetting.Equals("videooutput.aspect")) { @@ -672,10 +672,10 @@ void CGUIWindowSettingsCategory::CreateSettings() pControl->AddLabel(g_localizeStrings.Get(13509), RESAMPLE_REALLYHIGH); pControl->SetValue(pSettingInt->GetData()); } - else if (strSetting.Equals("weather.plugin")) + else if (strSetting.Equals("weather.script")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(GetSetting(pSetting->GetSetting())->GetID()); - FillInWeatherPlugins(pControl, g_guiSettings.GetString("weather.plugin")); + FillInWeatherScripts(pControl, g_guiSettings.GetString("weather.script")); } } @@ -1021,13 +1021,13 @@ void CGUIWindowSettingsCategory::UpdateSettings() CGUIButtonControl *pControl = (CGUIButtonControl *)GetControl(GetSetting(strSetting)->GetID()); pControl->SetLabel2(CWeather::GetAreaCity(pSetting->GetData())); } - else if (strSetting.Equals("weather.plugin")) + else if (strSetting.Equals("weather.script")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); if (pControl->GetCurrentLabel().Equals(g_localizeStrings.Get(13611))) - g_guiSettings.SetString("weather.plugin", ""); + g_guiSettings.SetString("weather.script", ""); else - g_guiSettings.SetString("weather.plugin", pControl->GetCurrentLabel()); + g_guiSettings.SetString("weather.script", pControl->GetCurrentLabel()); } else if (strSetting.Equals("musicfiles.trackformat")) { @@ -1063,16 +1063,6 @@ void CGUIWindowSettingsCategory::UpdateSettings() CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); pControl->SetEnabled(XFILE::CFile::Exists(RSSEDITOR_PATH) && g_guiSettings.GetBool("lookandfeel.enablerssfeeds")); } - else if (strSetting.Equals("musiclibrary.scrapersettings")) - { - CScraperParser parser; - bool enabled=false; - if (parser.Load("special://xbmc/system/scrapers/music/"+g_guiSettings.GetString("musiclibrary.scraper"))) - enabled = parser.HasFunction("GetSettings"); - - CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); - if (pControl) pControl->SetEnabled(enabled); - } else if (strSetting.Equals("videoplayer.synctype")) { CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); @@ -1098,12 +1088,12 @@ void CGUIWindowSettingsCategory::UpdateSettings() pControl->SetEnabled(enabled); } } - else if (strSetting.Equals("weather.pluginsettings")) + else if (strSetting.Equals("weather.scriptsettings")) { - // Create our base path - CStdString basepath = "special://home/plugins/weather/" + g_guiSettings.GetString("weather.plugin"); - CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); - if (pControl) pControl->SetEnabled(!g_guiSettings.GetString("weather.plugin").IsEmpty() && CScriptSettings::SettingsExist(basepath)); + //// Create our base path + //CStdString basepath = "special://home/plugins/weather/" + g_guiSettings.GetString("weather.plugin"); + //CGUIControl *pControl = (CGUIControl *)GetControl(pSettingControl->GetID()); + //if (pControl) pControl->SetEnabled(!g_guiSettings.GetString("weather.plugin").IsEmpty() && CScriptSettings::SettingsExist(basepath)); } #if defined(_LINUX) && !defined(__APPLE__) else if (strSetting.Equals("audiooutput.custompassthrough")) @@ -1147,33 +1137,22 @@ void CGUIWindowSettingsCategory::OnClick(CBaseSettingControl *pSettingControl) g_weatherManager.Refresh(); } } - else if (strSetting.Equals("weather.plugin")) + else if (strSetting.Equals("weather.script")) { g_weatherManager.Refresh(); } - else if (strSetting.Equals("weather.pluginsettings")) + else if (strSetting.Equals("weather.scriptsettings")) { - // Create our base path - CStdString basepath = "special://home/plugins/weather/" + g_guiSettings.GetString("weather.plugin"); - CGUIDialogPluginSettings::ShowAndGetInput(basepath); - // TODO: maybe have ShowAndGetInput return a bool if settings changed, then only reset weather if true. + CStdString name = g_guiSettings.GetString("weather.script"); + AddonPtr addon; + if (CAddonMgr::Get()->GetAddon(ADDON_PLUGIN, name, addon)) + { // TODO: maybe have ShowAndGetInput return a bool if settings changed, then only reset weather if true. + CGUIDialogAddonSettings::ShowAndGetInput(addon); + } g_weatherManager.Refresh(); } else if (strSetting.Equals("lookandfeel.rssedit")) CBuiltins::Execute("RunScript("RSSEDITOR_PATH")"); - else if (strSetting.Equals("musiclibrary.scrapersettings")) - { - CMusicDatabase database; - database.Open(); - SScraperInfo info; - database.GetScraperForPath("musicdb://",info); - - if (info.settings.LoadSettingsXML("special://xbmc/system/scrapers/music/" + info.strPath)) - CGUIDialogPluginSettings::ShowAndGetInput(info); - - database.SetScraperForPath("musicdb://",info); - database.Close(); - } // if OnClick() returns false, the setting hasn't changed or doesn't // require immediate update @@ -1218,7 +1197,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(CBaseSettingControl *pSettingC if (pControl->GetValue() == 0) pSettingString->SetData("None"); else - pSettingString->SetData( CVisualisation::GetCombinedName( pControl->GetCurrentLabel() ) ); + pSettingString->SetData(pControl->GetCurrentLabel()); } else if (strSetting.Equals("debug.showloginfo")) { @@ -1248,22 +1227,22 @@ void CGUIWindowSettingsCategory::OnSettingChanged(CBaseSettingControl *pSettingC else if (strSetting.Equals("musiclibrary.scraper")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); - FillInScrapers(pControl, pControl->GetCurrentLabel(), "music"); + FillInScrapers(pControl, pControl->GetCurrentLabel(), CONTENT_ALBUMS); } else if (strSetting.Equals("scrapers.moviedefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); - FillInScrapers(pControl, pControl->GetCurrentLabel(), "movies"); + FillInScrapers(pControl, pControl->GetCurrentLabel(), CONTENT_MOVIES); //TODO langify these } else if (strSetting.Equals("scrapers.tvshowdefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); - FillInScrapers(pControl, pControl->GetCurrentLabel(), "tvshows"); + FillInScrapers(pControl, pControl->GetCurrentLabel(), CONTENT_TVSHOWS); } else if (strSetting.Equals("scrapers.musicvideodefault")) { CGUISpinControlEx *pControl = (CGUISpinControlEx *)GetControl(pSettingControl->GetID()); - FillInScrapers(pControl, pControl->GetCurrentLabel(), "musicvideos"); + FillInScrapers(pControl, pControl->GetCurrentLabel(), CONTENT_MUSICVIDEOS); } else if (strSetting.Equals("videolibrary.cleanup")) { @@ -1710,7 +1689,7 @@ void CGUIWindowSettingsCategory::OnSettingChanged(CBaseSettingControl *pSettingC else if (iValue == 4) strScreenSaver = "Fanart Slideshow"; //Fanart Slideshow else - strScreenSaver = pControl->GetCurrentLabel() + ".xbs"; + strScreenSaver = pControl->GetCurrentLabel(); pSettingString->SetData(strScreenSaver); } else if (strSetting.Equals("screensaver.preview")) @@ -2468,60 +2447,36 @@ void CGUIWindowSettingsCategory::FillInVisualisations(CSetting *pSetting, int iC CGUIMessage msg(GUI_MSG_LABEL_RESET, iWinID, iControlID); g_windowManager.SendMessage(msg); } + vector<CStdString> vecVis; - //find visz.... - CFileItemList items; - CDirectory::GetDirectory("special://xbmc/visualisations/", items); - if (!CSpecialProtocol::XBMCIsHome()) - CDirectory::GetDirectory("special://home/visualisations/", items); + VECADDONS addons; - CVisualisationFactory visFactory; - CStdString strExtension; - for (int i = 0; i < items.Size(); ++i) + CAddonMgr::Get()->GetAddons(ADDON_VIZ, addons); + if (!addons.empty()) { - CFileItemPtr pItem = items[i]; - if (!pItem->m_bIsFolder) + for (unsigned int i = 0; i < addons.size(); i++) { - const char *visPath = (const char*)pItem->m_strPath; - - CUtil::GetExtension(pItem->m_strPath, strExtension); - if (strExtension == ".vis") // normal visualisation + const AddonPtr addon = addons.at(i); + boost::shared_ptr<CVisualisation> vis = boost::dynamic_pointer_cast<CVisualisation>(addon); + if (vis->HasSubModules()) { - if(!CVisualisation::IsValidVisualisation(pItem->m_strPath)) + vector<CStdString> modules; + if (!vis->GetSubModuleList(modules)) continue; - CStdString strLabel = pItem->GetLabel(); - vecVis.push_back( CVisualisation::GetFriendlyName( strLabel ) ); - } - else if ( strExtension == ".mvis" ) // multi visualisation with sub modules - { - CVisualisation* vis = visFactory.LoadVisualisation( visPath ); - if ( vis ) + else { - map<string, string> subModules; - map<string, string>::iterator iter; - string moduleName; - CStdString visName = pItem->GetLabel(); - visName = visName.Mid(0, visName.size() - 5); - - // get list of sub modules from the visualisation - vis->GetSubModules( subModules ); - - for ( iter=subModules.begin() ; iter!=subModules.end() ; iter++ ) - { - // each pair of the map is of the format 'module name' => 'module path' - moduleName = iter->first; - vecVis.push_back( CVisualisation::GetFriendlyName( visName.c_str(), moduleName.c_str() ).c_str() ); - CLog::Log(LOGDEBUG, "Module %s for visualisation %s", moduleName.c_str(), visPath); - } - delete vis; + for (unsigned i=0; i<modules.size(); i++) + vecVis.push_back(CVisualisation::GetFriendlyName(addon->Name(), modules[i])); } } + else + vecVis.push_back(addon->Name()); } } CStdString strDefaultVis = pSettingString->GetData(); if (!strDefaultVis.Equals("None")) - strDefaultVis = CVisualisation::GetFriendlyName( strDefaultVis ); + strDefaultVis = strDefaultVis; sort(vecVis.begin(), vecVis.end(), sortstringbyname()); @@ -2621,43 +2576,21 @@ void CGUIWindowSettingsCategory::FillInScreenSavers(CSetting *pSetting) pControl->AddLabel(g_localizeStrings.Get(108), 3); // PictureSlideShow pControl->AddLabel(g_localizeStrings.Get(20425), 4); // Fanart Slideshow - //find screensavers .... - CFileItemList items; - CDirectory::GetDirectory( "special://xbmc/screensavers/", items); - if (!CSpecialProtocol::XBMCIsHome()) - CDirectory::GetDirectory("special://home/screensavers/", items); - int iCurrentScr = -1; vector<CStdString> vecScr; - for (int i = 0; i < items.Size(); ++i) + VECADDONS addons; + + CAddonMgr::Get()->GetAddons(ADDON_SCREENSAVER, addons); + if (!addons.empty()) { - CFileItemPtr pItem = items[i]; - if (!pItem->m_bIsFolder) + for (unsigned int i = 0; i < addons.size(); i++) { - CStdString strExtension; - CUtil::GetExtension(pItem->m_strPath, strExtension); - if (strExtension == ".xbs") - { -#ifdef _LINUX - void *handle = dlopen(_P(pItem->m_strPath).c_str(), RTLD_LAZY); - if (!handle) - { - CLog::Log(LOGERROR, "FillInScreensavers: Unable to load %s, reason: %s", pItem->m_strPath.c_str(), dlerror()); - continue; - } - dlclose(handle); -#endif - CStdString strLabel = pItem->GetLabel(); - vecScr.push_back(strLabel.Mid(0, strLabel.size() - 4)); - } + const AddonPtr addon = addons.at(i); + vecScr.push_back(addon->Name()); } } CStdString strDefaultScr = pSettingString->GetData(); - CStdString strExtension; - CUtil::GetExtension(strDefaultScr, strExtension); - if (strExtension == ".xbs") - strDefaultScr.Delete(strDefaultScr.size() - 4, 4); sort(vecScr.begin(), vecScr.end(), sortstringbyname()); for (int i = 0; i < (int) vecScr.size(); ++i) @@ -2973,58 +2906,52 @@ void CGUIWindowSettingsCategory::FillInSortMethods(CSetting *pSetting, int windo delete state; } -void CGUIWindowSettingsCategory::FillInScrapers(CGUISpinControlEx *pControl, const CStdString& strSelected, const CStdString& strContent) +void CGUIWindowSettingsCategory::FillInScrapers(CGUISpinControlEx *pControl, const CStdString& strSelected, const CONTENT_TYPE& content) { - CFileItemList items; - if (strContent.Equals("music")) - CDirectory::GetDirectory("special://xbmc/system/scrapers/music",items,".xml",false); - else - CDirectory::GetDirectory("special://xbmc/system/scrapers/video",items,".xml",false); - int j=0; - int k=0; + VECADDONS addons; pControl->Clear(); - for ( int i=0;i<items.Size();++i) - { - if (items[i]->m_bIsFolder) - continue; - - CScraperParser parser; - if (parser.Load(items[i]->m_strPath)) - { - if (parser.GetContent() != strContent && !strContent.Equals("music")) - continue; - - if (parser.GetName().Equals(strSelected) || CUtil::GetFileName(items[i]->m_strPath).Equals(strSelected)) - { - if (strContent.Equals("music")) // native strContent would be albums or artists but we're using the same scraper for both - { - if (g_guiSettings.GetString("musiclibrary.scraper") != strSelected) - { - g_guiSettings.SetString("musiclibrary.scraper", CUtil::GetFileName(items[i]->m_strPath)); - - SScraperInfo info; - CMusicDatabase database; - info.strPath = g_guiSettings.GetString("musiclibrary.scraper"); - info.strContent = "albums"; - info.strTitle = parser.GetName(); + if (content == CONTENT_ALBUMS || content == CONTENT_ALBUMS || content == CONTENT_ARTISTS) + CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, CONTENT_ALBUMS); + else if (content == CONTENT_MOVIES) + CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, CONTENT_MOVIES); + else if (content == CONTENT_TVSHOWS || content == CONTENT_EPISODES) + CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, CONTENT_TVSHOWS); + else if (content == CONTENT_MUSICVIDEOS) + CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, CONTENT_MUSICVIDEOS); + else if (content == CONTENT_PROGRAMS) + CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, addons, CONTENT_PROGRAMS); + + if (addons.empty()) + { + pControl->AddLabel(g_localizeStrings.Get(231), 0); // "None" + pControl->SetValue(0); + return; + } - database.Open(); - database.SetScraperForPath("musicdb://",info); - database.Close(); - } - } - else if (strContent.Equals("movies")) - g_guiSettings.SetString("scrapers.moviedefault", CUtil::GetFileName(items[i]->m_strPath)); - else if (strContent.Equals("tvshows")) - g_guiSettings.SetString("scrapers.tvshowdefault", CUtil::GetFileName(items[i]->m_strPath)); - else if (strContent.Equals("musicvideos")) - g_guiSettings.SetString("scrapers.musicvideodefault", CUtil::GetFileName(items[i]->m_strPath)); - k = j; - } - pControl->AddLabel(parser.GetName(),j++); + int j = 0; + int k = 0; + for (IVECADDONS it = addons.begin(); it != addons.end(); it++) + { + if ((*it)->Name().Equals(strSelected)) + { + if (content == CONTENT_ALBUMS) // native strContent would be albums or artists but we're using the same scraper for both + g_guiSettings.SetString("musiclibrary.scraper", (*it)->Name()); + else if (content == CONTENT_MOVIES) + g_guiSettings.SetString("scrapers.moviedefault", (*it)->Name()); + else if (content == CONTENT_TVSHOWS) + g_guiSettings.SetString("scrapers.tvshowdefault", (*it)->Name()); + else if (content == CONTENT_MUSICVIDEOS) + g_guiSettings.SetString("scrapers.musicvideodefault", (*it)->Name()); + else if (content == CONTENT_PROGRAMS) + g_guiSettings.SetString("programfiles.defaultscraper", (*it)->Name()); + k = j; } + pControl->AddLabel((*it)->Name(),j++); } + if (j == 0) + pControl->AddLabel(g_localizeStrings.Get(231), 0); // "None" + pControl->SetValue(k); } @@ -3150,33 +3077,31 @@ void CGUIWindowSettingsCategory::FillInAudioDevices(CSetting* pSetting, bool Pas #endif } -void CGUIWindowSettingsCategory::FillInWeatherPlugins(CGUISpinControlEx *pControl, const CStdString& strSelected) +void CGUIWindowSettingsCategory::FillInWeatherScripts(CGUISpinControlEx *pControl, const CStdString& strSelected) { + VECADDONS addons; int j=0; int k=0; pControl->Clear(); // add our disable option pControl->AddLabel(g_localizeStrings.Get(13611), j++); - CFileItemList items; - if (CDirectory::GetDirectory("special://home/plugins/weather/", items, "/", false)) + //find weather scripts.... + CAddonMgr::Get()->GetAddons(ADDON_SCRIPT, addons); + if (!addons.empty()) { - for (int i=0; i<items.Size(); ++i) + for (unsigned int i = 0; i < addons.size(); i++) { + AddonPtr addon = addons.at(i); // create the full path to the plugin - CStdString plugin; - CStdString pluginPath = items[i]->m_strPath; - // remove slash at end so we can use the plugins folder as plugin name - CUtil::RemoveSlashAtEnd(pluginPath); - // add default.py to our plugin path to create the full path - CUtil::AddFileToFolder(pluginPath, "default.py", plugin); - if (XFILE::CFile::Exists(plugin)) + CStdString strFileName = addon->Path() + addon->LibName(); + if (XFILE::CFile::Exists(strFileName)) { // is this the users choice - if (CUtil::GetFileName(pluginPath).Equals(strSelected)) + if (addon->Name().Equals(strSelected)) k = j; // we want to use the plugins folder as name - pControl->AddLabel(CUtil::GetFileName(pluginPath), j++); + pControl->AddLabel(addon->Name(), j++); } } } diff --git a/xbmc/GUIWindowSettingsCategory.h b/xbmc/GUIWindowSettingsCategory.h index 701ed02d4e..178107abcc 100644 --- a/xbmc/GUIWindowSettingsCategory.h +++ b/xbmc/GUIWindowSettingsCategory.h @@ -25,6 +25,7 @@ #include "SettingsControls.h" #include "GUISettings.h" #include "utils/Stopwatch.h" +#include "IAddon.h" class CGUIWindowSettingsCategory : public CGUIWindow @@ -64,10 +65,10 @@ protected: void FillInNetworkInterfaces(CSetting *pSetting); void NetworkInterfaceChanged(void); - void FillInScrapers(CGUISpinControlEx *pControl, const CStdString& strSelected, const CStdString& strContent); + void FillInScrapers(CGUISpinControlEx *pControl, const CStdString& strSelected, const CONTENT_TYPE& content); void FillInAudioDevices(CSetting* pSetting, bool Passthrough = false); - void FillInWeatherPlugins(CGUISpinControlEx *pControl, const CStdString& strSelected); + void FillInWeatherScripts(CGUISpinControlEx *pControl, const CStdString& strSelected); virtual void SetupControls(); void CreateSettings(); diff --git a/xbmc/GUIWindowVideoBase.cpp b/xbmc/GUIWindowVideoBase.cpp index bd10cea68b..8c14d00f65 100644 --- a/xbmc/GUIWindowVideoBase.cpp +++ b/xbmc/GUIWindowVideoBase.cpp @@ -25,6 +25,8 @@ #include "utils/IMDB.h" #include "utils/RegExp.h" #include "utils/GUIInfoManager.h" +#include "utils/AddonManager.h" +#include "utils/IAddon.h" #include "GUIWindowVideoInfo.h" #include "GUIWindowVideoNav.h" #include "GUIDialogFileBrowser.h" @@ -68,6 +70,7 @@ using namespace XFILE; using namespace PLAYLIST; using namespace VIDEODATABASEDIRECTORY; using namespace VIDEO; +using namespace ADDON; #define CONTROL_BTNVIEWASICONS 2 #define CONTROL_BTNSORTBY 3 @@ -182,7 +185,6 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) } else if (iAction == ACTION_SHOW_INFO) { - SScraperInfo info; if (iItem < 0 || iItem >= m_vecItems->Size()) return false; @@ -191,11 +193,8 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) if (item->m_strPath.Equals("add") || item->IsParentFolder()) return false; - if (m_vecItems->IsPlugin() || m_vecItems->IsRSS()) - info.strContent = "plugin"; - else if(m_vecItems->IsLiveTV()) - info.strContent = "livetv"; - else + ADDON::ScraperPtr scraper; + if (!m_vecItems->IsPlugin() && !m_vecItems->IsRSS() && !m_vecItems->IsLiveTV()) { CStdString strDir; if (item->IsVideoDb() && @@ -209,9 +208,9 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) SScanSettings settings; int iFound; - m_database.GetScraperForPath(strDir, info, settings, iFound); + m_database.GetScraperForPath(strDir, scraper, settings, iFound); - if (info.strContent.IsEmpty() && + if (!scraper && !(m_database.HasMovieInfo(item->m_strPath) || m_database.HasTvShowInfo(strDir) || m_database.HasEpisodeInfo(item->m_strPath))) @@ -223,16 +222,16 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) CStdString strOldPath = item->m_strPath; item->m_strPath = strDir; - OnAssignContent(iItem,1, info, settings); + OnAssignContent(iItem,1, scraper, settings); item->m_strPath = strOldPath; return true; } - if (info.strContent.Equals("tvshows") && iFound == 1 && !settings.parent_name_root) // dont lookup on root tvshow folder + if (scraper->Content() == CONTENT_TVSHOWS && iFound == 1 && !settings.parent_name_root) // dont lookup on root tvshow folder return true; } - OnInfo(item.get(),info); + OnInfo(item.get(),scraper); return true; } @@ -266,7 +265,7 @@ bool CGUIWindowVideoBase::OnMessage(CGUIMessage& message) } else if (iControl == CONTROL_IMDB) { - OnManualIMDB(); + OnManualScrape(); } } break; @@ -300,11 +299,14 @@ void CGUIWindowVideoBase::UpdateButtons() CGUIMediaWindow::UpdateButtons(); } -void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const SScraperInfo& info) +void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const ADDON::ScraperPtr& scraper) { if (!pItem) return; + if (!scraper) + return; + if (pItem->IsParentFolder() || pItem->m_bIsShareOrDrive || pItem->m_strPath.Equals("add")) return; @@ -320,7 +322,7 @@ void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const SScraperInfo& info) } else { - if (item.m_bIsFolder && !info.strContent.Equals("tvshows")) + if (item.m_bIsFolder && scraper->Content() != CONTENT_TVSHOWS) { CFileItemList items; CDirectory::GetDirectory(item.m_strPath, items); @@ -351,8 +353,8 @@ void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const SScraperInfo& info) } } - bool modified = ShowIMDB(&item, info); - if (modified && !info.strContent.Equals("plugin") && !info.strContent.Equals("livetv") && + bool modified = ShowIMDB(&item, scraper); + if (modified && scraper->Content() != CONTENT_PLUGIN && (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_FILES || g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)) // since we can be called from the music library we need this check { @@ -383,7 +385,7 @@ void CGUIWindowVideoBase::OnInfo(CFileItem* pItem, const SScraperInfo& info) // and show the information. // 6. Check for a refresh, and if so, go to 3. -bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) +bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const ScraperPtr &info2) { /* CLog::Log(LOGDEBUG,"CGUIWindowVideoBase::ShowIMDB"); @@ -399,7 +401,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) CVideoInfoScanner scanner; scanner.m_IMDB.SetScraperInfo(info2); - SScraperInfo info(info2); // use this as nfo might change it.. + ScraperPtr info(info2); // use this as nfo might change it.. if (!pDlgProgress) return false; if (!pDlgSelect) return false; @@ -413,7 +415,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) movieDetails.Reset(); m_database.Open(); // since we can be called from the music library - if (info.strContent.Equals("movies")) + if (info->Content() == CONTENT_MOVIES) { if (m_database.HasMovieInfo(item->m_strPath)) { @@ -421,7 +423,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) m_database.GetMovieInfo(item->m_strPath, movieDetails); } } - if (info.strContent.Equals("tvshows")) + if (info->Content() == CONTENT_TVSHOWS) { if (item->m_bIsFolder) { @@ -462,7 +464,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) } } } - if (info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_MUSICVIDEOS) { if (m_database.HasMusicVideoInfo(item->m_strPath)) { @@ -470,13 +472,12 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) m_database.GetMusicVideoInfo(item->m_strPath, movieDetails); } } - if (info.strContent.Equals("plugin") - || info.strContent.Equals("livetv")) + if (info->Content() == CONTENT_PLUGIN) { if (!item->HasVideoInfoTag()) return false; movieDetails = *item->GetVideoInfoTag(); - movieDetails.m_strIMDBNumber = "xx" + info.strContent; // disable refresh+get thumb button + movieDetails.m_strIMDBNumber = "xx" + ADDON::TranslateContent(info->Content()); // disable refresh+get thumb button bHasInfo = true; } @@ -484,7 +485,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) m_database.Close(); if (bHasInfo) { - if (info.strContent.IsEmpty()) // disable refresh button + if (info->Content() == CONTENT_NONE) // disable refresh button movieDetails.m_strIMDBNumber = "xx"+movieDetails.m_strIMDBNumber; *item->GetVideoInfoTag() = movieDetails; pDlgInfo->SetMovie(item); @@ -510,21 +511,18 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) m_database.Open(); // 2. Look for a nfo File to get the search URL SScanSettings settings; - m_database.GetScraperForPath(item->m_strPath,info,settings); + ADDON::AddonPtr addon; - if (!info.settings.GetPluginRoot() && info.settings.GetSettings().IsEmpty()) // check for settings, if they are around load defaults - to workaround the nastyness + if (!m_database.GetScraperForPath(item->m_strPath,info,settings)) { - CScraperParser parser; - CStdString strPath; - if (!info.strContent.IsEmpty()) - strPath = "special://xbmc/system/scrapers/video/"+info.strPath; - if (!strPath.IsEmpty() && parser.Load(strPath) && parser.HasFunction("GetSettings")) - { - info.settings.LoadSettingsXML("special://xbmc/system/scrapers/video/" + info.strPath); - info.settings.SaveFromDefault(); - } + if (!ADDON::CAddonMgr::Get()->GetDefault(ADDON::ADDON_SCRAPER, addon, info->Content())) + return false; } + info = boost::dynamic_pointer_cast<ADDON::CScraper>(addon); + if (!info) + return false; + bool ignoreNfo(false); CNfoFile::NFOResult nfoResult = scanner.CheckForNFOFile(item,settings.parent_name_root,info,scrUrl); if (nfoResult == CNfoFile::ERROR_NFO) @@ -548,7 +546,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) // 4. if we don't have an url, or need to refresh the search // then do the web search IMDB_MOVIELIST movielist; - if (info.strContent.Equals("tvshows") && !item->m_bIsFolder) + if (info->Content() == CONTENT_TVSHOWS && !item->m_bIsFolder) hasDetails = true; if (!hasDetails && (scrUrl.m_url.size() == 0 || needsRefresh)) @@ -556,7 +554,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) // 4a. show dialog that we're busy querying www.imdb.com CStdString strHeading; scanner.m_IMDB.SetScraperInfo(info); - strHeading.Format(g_localizeStrings.Get(197),info.strTitle.c_str()); + strHeading.Format(g_localizeStrings.Get(197),info->Name().c_str()); pDlgProgress->SetHeading(strHeading); pDlgProgress->SetLine(0, movieName); pDlgProgress->SetLine(1, ""); @@ -572,7 +570,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) if (movielist.size() > 0) { int iString = 196; - if (info.strContent.Equals("tvshows")) + if (info->Content() == CONTENT_TVSHOWS) iString = 20356; pDlgSelect->SetHeading(iString); pDlgSelect->Reset(); @@ -613,7 +611,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) // Prompt the user to input the movieName int iString = 16009; - if (info.strContent.Equals("tvshows")) + if (info->Content() == CONTENT_TVSHOWS) iString = 20357; if (!CGUIDialogKeyboard::ShowAndGetInput(movieName, g_localizeStrings.Get(iString), false)) { @@ -647,14 +645,14 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) CUtil::GetDirectory(strPath,list.m_strPath); int iString=198; - if (info.strContent.Equals("tvshows")) + if (info->Content() == CONTENT_TVSHOWS) { if (item->m_bIsFolder) iString = 20353; else iString = 20361; } - if (info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_MUSICVIDEOS) iString = 20394; pDlgProgress->SetHeading(iString); pDlgProgress->SetLine(0, movieName); @@ -664,13 +662,13 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) pDlgProgress->Progress(); if (bHasInfo) { - if (info.strContent.Equals("movies")) + if (info->Content() == CONTENT_MOVIES) m_database.DeleteMovie(item->m_strPath); - if (info.strContent.Equals("tvshows") && !item->m_bIsFolder) + if (info->Content() == CONTENT_TVSHOWS && !item->m_bIsFolder) m_database.DeleteEpisode(item->m_strPath,movieDetails.m_iDbId); - if (info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_MUSICVIDEOS) m_database.DeleteMusicVideo(item->m_strPath); - if (info.strContent.Equals("tvshows") && item->m_bIsFolder) + if (info->Content() == CONTENT_TVSHOWS && item->m_bIsFolder) { if (pDlgInfo->RefreshAll()) m_database.DeleteTvShow(item->m_strPath); @@ -680,11 +678,11 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) } if (scanner.RetrieveVideoInfo(list,settings.parent_name_root,info,!pDlgInfo->RefreshAll(),&scrUrl,pDlgProgress,ignoreNfo)) { - if (info.strContent.Equals("movies")) + if (info->Content() == CONTENT_MOVIES) m_database.GetMovieInfo(item->m_strPath,movieDetails); - if (info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_MUSICVIDEOS) m_database.GetMusicVideoInfo(item->m_strPath,movieDetails); - if (info.strContent.Equals("tvshows")) + if (info->Content() == CONTENT_TVSHOWS) { // update tvshow info to get updated episode numbers if (item->m_bIsFolder) @@ -694,7 +692,7 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) } // set path hash - if (info.strContent.Equals("movies") || info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_MOVIES || info->Content() == CONTENT_MUSICVIDEOS) { CStdString hash, strParent; CFileItemList items; @@ -767,8 +765,11 @@ bool CGUIWindowVideoBase::ShowIMDB(CFileItem *item, const SScraperInfo& info2) return listNeedsUpdating; } -void CGUIWindowVideoBase::OnManualIMDB() +void CGUIWindowVideoBase::OnManualScrape() { + // NOTE! this only works for movies + // previous OnManualIMDB only worked for IMDb, so not a regression! + // if we were tracking current content type this would work for all content CStdString strInput; if (!CGUIDialogKeyboard::ShowAndGetInput(strInput, g_localizeStrings.Get(16009), false)) return; @@ -777,12 +778,21 @@ void CGUIWindowVideoBase::OnManualIMDB() item.m_strPath = "special://temp/"; CFile::Delete(item.GetCachedVideoThumb().c_str()); - SScraperInfo info; - info.strContent = "movies"; - info.strPath = "imdb.xml"; - info.strTitle = "IMDb"; + ScraperPtr scraper; + m_database.Open(); + if (!m_database.GetScraperForPath(m_vecItems->m_strPath, scraper)) + { + AddonPtr addon; + if (CAddonMgr::Get()->GetDefault(ADDON_SCRAPER, addon, CONTENT_MOVIES)) + { + scraper = boost::dynamic_pointer_cast<CScraper>(addon); + } + } + + if (!scraper) + return; - ShowIMDB(&item,info); + ShowIMDB(&item,scraper); return; } @@ -1234,7 +1244,7 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) case CONTEXT_BUTTON_INFO: { - SScraperInfo info; + ADDON::ScraperPtr info; VIDEO::SScanSettings settings; GetScraperForItem(item.get(), info, settings); @@ -1253,7 +1263,7 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) { if( !item) return false; - SScraperInfo info; + ADDON::ScraperPtr info; SScanSettings settings; GetScraperForItem(item.get(), info, settings); CStdString strPath = item->m_strPath; @@ -1263,7 +1273,7 @@ bool CGUIWindowVideoBase::OnContextButton(int itemNumber, CONTEXT_BUTTON button) if (item->IsVideoDb()) strPath = item->GetVideoInfoTag()->m_strPath; - if (info.strContent.IsEmpty()) + if (info->Content() == CONTENT_NONE) return false; if (item->m_bIsFolder) @@ -1926,19 +1936,19 @@ void CGUIWindowVideoBase::OnSearchItemFound(const CFileItem* pSelItem) m_viewControl.SetFocused(); } -int CGUIWindowVideoBase::GetScraperForItem(CFileItem *item, SScraperInfo &info, SScanSettings& settings) +int CGUIWindowVideoBase::GetScraperForItem(CFileItem *item, ADDON::ScraperPtr &info, SScanSettings& settings) { if (!item) return 0; if (m_vecItems->IsPlugin() || m_vecItems->IsRSS()) { - info.strContent = "plugin"; + info.reset(); return 0; } else if(m_vecItems->IsLiveTV()) { - info.strContent = "livetv"; + info.reset(); return 0; } @@ -1951,7 +1961,7 @@ int CGUIWindowVideoBase::GetScraperForItem(CFileItem *item, SScraperInfo &info, return found; } -void CGUIWindowVideoBase::OnScan(const CStdString& strPath, const SScraperInfo& info, const SScanSettings& settings) +void CGUIWindowVideoBase::OnScan(const CStdString& strPath, const ScraperPtr& info, const SScanSettings& settings) { CGUIDialogVideoScan* pDialog = (CGUIDialogVideoScan*)g_windowManager.GetWindow(WINDOW_DIALOG_VIDEO_SCAN); if (pDialog) diff --git a/xbmc/GUIWindowVideoBase.h b/xbmc/GUIWindowVideoBase.h index 506339c485..0ec7ec9b85 100644 --- a/xbmc/GUIWindowVideoBase.h +++ b/xbmc/GUIWindowVideoBase.h @@ -38,8 +38,8 @@ public: int GetResumeItemOffset(const CFileItem *item); void AddToDatabase(int iItem); - static void OnScan(const CStdString& strPath, const SScraperInfo& info, const VIDEO::SScanSettings& settings); - virtual void OnInfo(CFileItem* pItem, const SScraperInfo& info); + static void OnScan(const CStdString& strPath, const ADDON::ScraperPtr& info, const VIDEO::SScanSettings& settings); + virtual void OnInfo(CFileItem* pItem, const ADDON::ScraperPtr& scraper); virtual void OnStreamDetails(const CStreamDetails &details, const CStdString &strFileName, long lFileId); static void MarkWatched(const CFileItemPtr &pItem, bool mark); static void UpdateVideoTitle(const CFileItem* pItem); @@ -61,7 +61,7 @@ protected: virtual void GetContextButtons(int itemNumber, CContextButtons &buttons); void GetNonContextButtons(int itemNumber, CContextButtons &buttons); virtual bool OnContextButton(int itemNumber, CONTEXT_BUTTON button); - virtual void OnAssignContent(int iItem, int iFound, SScraperInfo& info, VIDEO::SScanSettings& settings) {}; + virtual void OnAssignContent(int iItem, int iFound, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings) {}; virtual void OnUnAssignContent(int iItem) {}; virtual void OnQueueItem(int iItem); virtual void OnDeleteItem(CFileItemPtr pItem); @@ -76,9 +76,9 @@ protected: virtual bool OnPlayMedia(int iItem); void LoadPlayList(const CStdString& strPlayList, int iPlayList = PLAYLIST_VIDEO); - bool ShowIMDB(CFileItem *item, const SScraperInfo& info); + bool ShowIMDB(CFileItem *item, const ADDON::ScraperPtr& content); - void OnManualIMDB(); + void OnManualScrape(); bool CheckMovie(const CStdString& strFileName); void AddItemToPlayList(const CFileItemPtr &pItem, CFileItemList &queuedItems); @@ -86,7 +86,7 @@ protected: void OnSearch(); void OnSearchItemFound(const CFileItem* pSelItem); - int GetScraperForItem(CFileItem *item, SScraperInfo &info, VIDEO::SScanSettings& settings); + int GetScraperForItem(CFileItem *item, ADDON::ScraperPtr &info, VIDEO::SScanSettings& settings); CGUIDialogProgress* m_dlgProgress; CVideoDatabase m_database; diff --git a/xbmc/GUIWindowVideoFiles.cpp b/xbmc/GUIWindowVideoFiles.cpp index 64341d7dcd..60c9828e8f 100644 --- a/xbmc/GUIWindowVideoFiles.cpp +++ b/xbmc/GUIWindowVideoFiles.cpp @@ -274,13 +274,13 @@ bool CGUIWindowVideoFiles::GetDirectory(const CStdString &strDirectory, CFileIte if (!CGUIWindowVideoBase::GetDirectory(strDirectory, items)) return false; - SScraperInfo info2; + ADDON::ScraperPtr info2; m_stackingAvailable = true; m_cleaningAvailable = true; - if ((m_database.GetScraperForPath(strDirectory,info2) && info2.strContent.Equals("tvshows")) || items.IsTuxBox()) + if ((m_database.GetScraperForPath(strDirectory,info2) && info2->Content() == CONTENT_TVSHOWS) || items.IsTuxBox()) { // dont stack or clean strings in tv dirs m_stackingAvailable = false; m_cleaningAvailable = false; @@ -288,8 +288,8 @@ bool CGUIWindowVideoFiles::GetDirectory(const CStdString &strDirectory, CFileIte else if (!items.IsStack() && g_settings.m_iMyVideoStack != STACK_NONE) items.Stack(); - if ((!info2.strContent.IsEmpty() && !info2.strContent.Equals("None")) && items.GetContent().IsEmpty()) - items.SetContent(info2.strContent.c_str()); + if (info2 && info2->Content() != CONTENT_NONE) + items.SetContent(ADDON::TranslateContent(info2->Content())); else items.SetContent("files"); @@ -313,11 +313,6 @@ void CGUIWindowVideoFiles::OnPrepareFileItems(CFileItemList &items) } } -bool CGUIWindowVideoFiles::OnClick(int iItem) -{ - return CGUIWindowVideoBase::OnClick(iItem); -} - bool CGUIWindowVideoFiles::OnPlayMedia(int iItem) { if ( iItem < 0 || iItem >= (int)m_vecItems->Size() ) return false; @@ -385,8 +380,9 @@ bool CGUIWindowVideoFiles::OnUnAssignContent(int iItem, int label1, int label2, { if (!bCanceled) { - SScraperInfo info; + ADDON::ScraperPtr info; SScanSettings settings; + settings.exclude = true; m_database.SetScraperForPath(m_vecItems->Get(iItem)->m_strPath,info,settings); } } @@ -394,42 +390,35 @@ bool CGUIWindowVideoFiles::OnUnAssignContent(int iItem, int label1, int label2, return false; } -void CGUIWindowVideoFiles::OnAssignContent(int iItem, int iFound, SScraperInfo& info, SScanSettings& settings) +void CGUIWindowVideoFiles::OnAssignContent(int iItem, int iFound, ADDON::ScraperPtr& info, SScanSettings& settings) { CFileItemPtr item = m_vecItems->Get(iItem); bool bScan=false; if (iFound == 0) { - m_database.GetScraperForPath(item->m_strPath,info, settings,iFound); + m_database.GetScraperForPath(item->m_strPath,info,settings,iFound); } - SScraperInfo info2 = info; - SScanSettings settings2 = settings; - if (CGUIDialogContentSettings::Show(info2, settings2, bScan)) + if (CGUIDialogContentSettings::Show(info, settings, bScan)) { - if((info2.strContent.IsEmpty() || info2.strContent.Equals("None")) && - (!info.strContent.IsEmpty() && !info.strContent.Equals("None"))) + if(settings.exclude || !info) { OnUnAssignContent(iItem,20375,20340,20341); } - if (!info.strContent.IsEmpty() && - !info2.strContent.IsEmpty() && - !info.strContent.Equals("None") && - (info2.strContent != info.strContent || - !info.strPath.Equals(info2.strPath))) + else { if (OnUnAssignContent(iItem,20442,20443,20444)) bScan = true; } m_database.Open(); - m_database.SetScraperForPath(item->m_strPath,info2,settings2); + m_database.SetScraperForPath(item->m_strPath,info,settings); m_database.Close(); - if (bScan) + if (!settings.exclude && bScan) { - GetScraperForItem(item.get(),info2,settings2); - OnScan(item->m_strPath,info2,settings2); + GetScraperForItem(item.get(),info,settings); + OnScan(item->m_strPath,info,settings); } } } @@ -495,11 +484,11 @@ void CGUIWindowVideoFiles::GetContextButtons(int itemNumber, CContextButtons &bu buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333); CVideoDatabase database; database.Open(); - SScraperInfo info; + ADDON::ScraperPtr info; if (item && database.GetScraperForPath(item->m_strPath,info)) { - if (!info.strPath.IsEmpty() && !info.strContent.IsEmpty()) + if (info->Content() != CONTENT_NONE) if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())) buttons.Add(CONTEXT_BUTTON_SCAN, 13349); } @@ -515,14 +504,15 @@ void CGUIWindowVideoFiles::GetContextButtons(int itemNumber, CContextButtons &bu buttons.Add(CONTEXT_BUTTON_STOP_SCANNING, 13353); if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].canWriteDatabases() || g_passwordManager.bMasterUser) { - SScraperInfo info; + ADDON::ScraperPtr info; VIDEO::SScanSettings settings; - int iFound = GetScraperForItem(item.get(), info, settings); + GetScraperForItem(item.get(), info, settings); int infoString = 13346; - if (info.strContent.Equals("tvshows")) + + if (info && info->Content() == CONTENT_TVSHOWS) infoString = item->m_bIsFolder ? 20351 : 20352; - if (info.strContent.Equals("musicvideos")) + if (info && info->Content() == CONTENT_MUSICVIDEOS) infoString = 20393; if (item->m_bIsFolder && !item->IsParentFolder()) @@ -530,19 +520,22 @@ void CGUIWindowVideoFiles::GetContextButtons(int itemNumber, CContextButtons &bu if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())) if (!item->IsPlayList() && !item->IsLiveTV()) buttons.Add(CONTEXT_BUTTON_SET_CONTENT, 20333); - if (iFound==0) + if (!info) { // scraper not set - allow movie information or set content CStdString strPath(item->m_strPath); CUtil::AddSlashAtEnd(strPath); - if ((info.strContent.Equals("movies") && m_database.HasMovieInfo(strPath)) || - (info.strContent.Equals("tvshows") && m_database.HasTvShowInfo(strPath))) + if (m_database.HasMovieInfo(strPath) || m_database.HasTvShowInfo(strPath)) buttons.Add(CONTEXT_BUTTON_INFO, infoString); } else { // scraper found - allow movie information, scan for new content, or set different type of content - if (!info.strContent.Equals("musicvideos")) + if (info->Content() == CONTENT_TVSHOWS) + infoString = item->m_bIsFolder ? 20351 : 20352; + if (info->Content() == CONTENT_MUSICVIDEOS) + infoString = 20393; + if (info->Content() != CONTENT_MUSICVIDEOS) buttons.Add(CONTEXT_BUTTON_INFO, infoString); - if (!info.strPath.IsEmpty() && !info.strContent.IsEmpty()) + if (info->Content() != CONTENT_NONE) if (!pScanDlg || (pScanDlg && !pScanDlg->IsScanning())) buttons.Add(CONTEXT_BUTTON_SCAN, 13349); } @@ -550,11 +543,9 @@ void CGUIWindowVideoFiles::GetContextButtons(int itemNumber, CContextButtons &bu else { // single file - if ((info.strContent.Equals("movies") && (iFound > 0 || - m_database.HasMovieInfo(item->m_strPath))) || - m_database.HasEpisodeInfo(item->m_strPath) || - info.strContent.Equals("livetv") || - info.strContent.Equals("musicvideos")) + if ( (info && m_database.HasMovieInfo(item->m_strPath)) || + m_database.HasEpisodeInfo(item->m_strPath) || + (info && info->Content() == CONTENT_MUSICVIDEOS) ) { buttons.Add(CONTEXT_BUTTON_INFO, infoString); } @@ -612,8 +603,11 @@ bool CGUIWindowVideoFiles::OnContextButton(int itemNumber, CONTEXT_BUTTON button { if (CGUIDialogContextMenu::OnContextButton("video", item, button)) { - if (button == CONTEXT_BUTTON_REMOVE_SOURCE) - OnUnAssignContent(itemNumber,20375,20340,20341); + //TODO should we search DB for entries from plugins? + if (button == CONTEXT_BUTTON_REMOVE_SOURCE && !item->IsPlugin()) + { + OnUnAssignContent(itemNumber,20375,20340,20341); + } Update(""); return true; } @@ -627,7 +621,7 @@ bool CGUIWindowVideoFiles::OnContextButton(int itemNumber, CONTEXT_BUTTON button case CONTEXT_BUTTON_SET_CONTENT: { - SScraperInfo info; + ADDON::ScraperPtr info; SScanSettings settings; if (item->HasVideoInfoTag()) // files view shouldn't need this check I think? m_database.GetScraperForPath(item->GetVideoInfoTag()->m_strPath, info, settings); diff --git a/xbmc/GUIWindowVideoFiles.h b/xbmc/GUIWindowVideoFiles.h index b99f24dedb..04b25b44b0 100644 --- a/xbmc/GUIWindowVideoFiles.h +++ b/xbmc/GUIWindowVideoFiles.h @@ -43,12 +43,11 @@ protected: virtual void AddFileToDatabase(const CFileItem* pItem); virtual void OnPrepareFileItems(CFileItemList &items); virtual void UpdateButtons(); - virtual bool OnClick(int iItem); virtual void GetContextButtons(int itemNumber, CContextButtons &buttons); virtual bool OnContextButton(int itemNumber, CONTEXT_BUTTON button); virtual void OnQueueItem(int iItem); - virtual void OnAssignContent(int iItem, int iFound, SScraperInfo& info, VIDEO::SScanSettings& settings); + virtual void OnAssignContent(int iItem, int iFound, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings); virtual bool OnUnAssignContent(int iItem, int label1, int label2, int label3); virtual void LoadPlayList(const CStdString& strFileName); diff --git a/xbmc/GUIWindowVideoNav.cpp b/xbmc/GUIWindowVideoNav.cpp index 2d12c486cf..f606cc5d48 100644 --- a/xbmc/GUIWindowVideoNav.cpp +++ b/xbmc/GUIWindowVideoNav.cpp @@ -36,6 +36,7 @@ #include "PlayListFactory.h" #include "GUIDialogVideoScan.h" #include "GUIDialogOK.h" +#include "AddonManager.h" #include "PartyModeManager.h" #include "MusicDatabase.h" #include "GUIWindowManager.h" @@ -787,22 +788,19 @@ void CGUIWindowVideoNav::FrameMove() CGUIWindowVideoBase::FrameMove(); } -void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, const SScraperInfo& info) +void CGUIWindowVideoNav::OnInfo(CFileItem* pItem, ADDON::ScraperPtr& scraper) { - SScraperInfo info2(info); m_database.Open(); // since we can be called from the music library without being inited if (pItem->IsVideoDb()) - m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath,info2); - else if (m_vecItems->IsPlugin()) - info2.strContent = "plugin"; + m_database.GetScraperForPath(pItem->GetVideoInfoTag()->m_strPath,scraper); else { CStdString strPath,strFile; CUtil::Split(pItem->m_strPath,strPath,strFile); - m_database.GetScraperForPath(strPath,info2); + m_database.GetScraperForPath(strPath,scraper); } m_database.Close(); - CGUIWindowVideoBase::OnInfo(pItem,info2); + CGUIWindowVideoBase::OnInfo(pItem,scraper); } bool CGUIWindowVideoNav::CanDelete(const CStdString& strPath) @@ -1056,13 +1054,13 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt } else { - SScraperInfo info; + ADDON::ScraperPtr info; VIDEO::SScanSettings settings; GetScraperForItem(item.get(), info, settings); - if (info.strContent.Equals("tvshows")) + if (info && info->Content() == CONTENT_TVSHOWS) buttons.Add(CONTEXT_BUTTON_INFO, item->m_bIsFolder ? 20351 : 20352); - else if (info.strContent.Equals("musicvideos")) + else if (info && info->Content() == CONTENT_MUSICVIDEOS) buttons.Add(CONTEXT_BUTTON_INFO,20393); else if (!item->m_bIsFolder && !item->m_strPath.Left(19).Equals("newsmartplaylist://")) buttons.Add(CONTEXT_BUTTON_INFO, 13346); @@ -1107,7 +1105,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt else buttons.Add(CONTEXT_BUTTON_UPDATE_TVSHOW, 13349); } - if ((info.strContent.Equals("tvshows") && item->m_bIsFolder) || + if ((info && info->Content() == CONTENT_TVSHOWS && item->m_bIsFolder) || (item->IsVideoDb() && item->HasVideoInfoTag() && !item->m_bIsFolder)) { if (item->m_bIsFolder || item->GetVideoInfoTag()->m_playCount > 0) @@ -1149,7 +1147,7 @@ void CGUIWindowVideoNav::GetContextButtons(int itemNumber, CContextButtons &butt if (item->IsVideoDb() && item->HasVideoInfoTag() && (!item->m_bIsFolder || node == NODE_TYPE_TITLE_TVSHOWS)) { - if (info.strContent.Equals("tvshows")) + if (info && info->Content() == CONTENT_TVSHOWS) { if(item->GetVideoInfoTag()->m_iBookmarkId != -1 && item->GetVideoInfoTag()->m_iBookmarkId != 0) @@ -1442,9 +1440,8 @@ bool CGUIWindowVideoNav::OnContextButton(int itemNumber, CONTEXT_BUTTON button) } case CONTEXT_BUTTON_UPDATE_LIBRARY: { - SScraperInfo info; VIDEO::SScanSettings settings; - OnScan("",info,settings); + OnScan("",ADDON::ScraperPtr(),settings); return true; } case CONTEXT_BUTTON_UNLINK_MOVIE: diff --git a/xbmc/GUIWindowVideoNav.h b/xbmc/GUIWindowVideoNav.h index fa77c07026..ee79241758 100644 --- a/xbmc/GUIWindowVideoNav.h +++ b/xbmc/GUIWindowVideoNav.h @@ -38,7 +38,7 @@ public: virtual void FrameMove(); virtual void OnPrepareFileItems(CFileItemList &items); - virtual void OnInfo(CFileItem* pItem, const SScraperInfo&info); + virtual void OnInfo(CFileItem* pItem, ADDON::ScraperPtr &info); static bool CanDelete(const CStdString& strPath); static bool DeleteItem(CFileItem* pItem, bool bUnavailable=false); diff --git a/xbmc/GUIWindowVisualisation.cpp b/xbmc/GUIWindowVisualisation.cpp index 6ebc6a2693..0c98eb5cc8 100644 --- a/xbmc/GUIWindowVisualisation.cpp +++ b/xbmc/GUIWindowVisualisation.cpp @@ -21,6 +21,7 @@ #include "GUIWindowVisualisation.h" #include "GUIVisualisationControl.h" +#include "visualizations/Visualisation.h" #include "Application.h" #include "GUIDialogMusicOSD.h" #include "GUIUserMessages.h" @@ -32,6 +33,7 @@ #include "AdvancedSettings.h" using namespace MUSIC_INFO; +using namespace ADDON; #define TRANSISTION_COUNT 50 // 1 second #define TRANSISTION_LENGTH 200 // 4 seconds @@ -47,14 +49,21 @@ CGUIWindowVisualisation::CGUIWindowVisualisation(void) m_bShowPreset = false; } -CGUIWindowVisualisation::~CGUIWindowVisualisation(void) -{ -} - bool CGUIWindowVisualisation::OnAction(const CAction &action) { + VIS_ACTION visAction = VIS_ACTION_NONE; switch (action.GetID()) { + case ACTION_VIS_PRESET_NEXT: + visAction = VIS_ACTION_NEXT_PRESET; break; + case ACTION_VIS_PRESET_PREV: + visAction = VIS_ACTION_PREV_PRESET; break; + case ACTION_VIS_PRESET_RANDOM: + visAction = VIS_ACTION_RANDOM_PRESET; break; + case ACTION_VIS_RATE_PRESET_PLUS: + visAction = VIS_ACTION_RATE_PRESET_PLUS; break; + case ACTION_VIS_RATE_PRESET_MINUS: + visAction = VIS_ACTION_RATE_PRESET_MINUS; break; case ACTION_SHOW_INFO: { if (!m_initTimer || g_settings.m_bMyMusicSongThumbInVis) @@ -73,19 +82,6 @@ bool CGUIWindowVisualisation::OnAction(const CAction &action) case ACTION_VIS_PRESET_LOCK: { // show the locked icon + fall through so that the vis handles the locking - CGUIMessage msg(GUI_MSG_GET_VISUALISATION, 0, 0); - g_windowManager.SendMessage(msg); - if (msg.GetPointer()) - { - CVisualisation *pVis = (CVisualisation *)msg.GetPointer(); - char** pPresets=NULL; - int currpreset=0, numpresets=0; - bool locked; - - pVis->GetPresets(&pPresets,&currpreset,&numpresets,&locked); - if (numpresets == 1 || !pPresets) - return true; - } if (!m_bShowPreset) { m_lockedTimer = START_FADE_LENGTH; @@ -127,10 +123,10 @@ bool CGUIWindowVisualisation::OnAction(const CAction &action) } break;*/ } - // default action is to send to the visualisation first - CGUIVisualisationControl *pVisControl = (CGUIVisualisationControl *)GetControl(CONTROL_VIS); - if (pVisControl && pVisControl->OnAction(action)) - return true; + + if (visAction != VIS_ACTION_NONE && m_addon) + return m_addon->OnAction(visAction); + return CGUIWindow::OnAction(action); } @@ -138,30 +134,25 @@ bool CGUIWindowVisualisation::OnMessage(CGUIMessage& message) { switch ( message.GetMessage() ) { - case GUI_MSG_PLAYBACK_STARTED: - { - CGUIVisualisationControl *pVisControl = (CGUIVisualisationControl *)GetControl(CONTROL_VIS); - if (pVisControl) - return pVisControl->OnMessage(message); - } - break; case GUI_MSG_GET_VISUALISATION: { -// message.SetControlID(CONTROL_VIS); - CGUIVisualisationControl *pVisControl = (CGUIVisualisationControl *)GetControl(CONTROL_VIS); - if (pVisControl) - message.SetPointer(pVisControl->GetVisualisation()); - return true; + if (m_addon) + message.SetPointer(m_addon.get()); + return m_addon; } break; case GUI_MSG_VISUALISATION_ACTION: + { + CAction action(message.GetParam1()); + return OnAction(action); + } + case GUI_MSG_PLAYBACK_STARTED: + { + if (IsActive() && m_addon) { - // message.SetControlID(CONTROL_VIS); - CGUIVisualisationControl *pVisControl = (CGUIVisualisationControl *)GetControl(CONTROL_VIS); - if (pVisControl) - return pVisControl->OnMessage(message); + m_addon->UpdateTrack(); } - break; + } case GUI_MSG_WINDOW_DEINIT: { if (IsActive()) // save any changed settings from the OSD @@ -183,6 +174,12 @@ bool CGUIWindowVisualisation::OnMessage(CGUIMessage& message) return true; } + AddonPtr viz; + CAddonMgr::Get()->GetDefault(ADDON_VIZ, viz); + m_addon = boost::dynamic_pointer_cast<CVisualisation>(viz); + if (!m_addon) + return false; + // hide or show the preset button(s) g_infoManager.SetShowCodec(m_bShowPreset); g_infoManager.SetShowInfo(true); // always show the info initially. @@ -205,6 +202,25 @@ bool CGUIWindowVisualisation::OnMessage(CGUIMessage& message) return CGUIWindow::OnMessage(message); } +void CGUIWindowVisualisation::OnWindowLoaded() +{ + if (m_addon) + { + CGUIVisualisationControl *pVisControl = (CGUIVisualisationControl *)GetControl(CONTROL_VIS); + if (pVisControl) + pVisControl->LoadAddon(m_addon); + } +} + +bool CGUIWindowVisualisation::UpdateTrack() +{ + if (m_addon) + { + return m_addon->UpdateTrack(); + } + return false; +} + bool CGUIWindowVisualisation::OnMouseEvent(const CPoint &point, const CMouseEvent &event) { if (event.m_id == ACTION_MOUSE_RIGHT_CLICK) @@ -231,7 +247,7 @@ bool CGUIWindowVisualisation::OnMouseEvent(const CPoint &point, const CMouseEven void CGUIWindowVisualisation::FrameMove() { - g_application.ResetScreenSaver(); + g_application.ResetScreenSaver(); //why here? // check for a tag change const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag(); if (tag && *tag != m_tag) diff --git a/xbmc/GUIWindowVisualisation.h b/xbmc/GUIWindowVisualisation.h index a17f45e4e0..73cd5aa4fe 100644 --- a/xbmc/GUIWindowVisualisation.h +++ b/xbmc/GUIWindowVisualisation.h @@ -24,20 +24,27 @@ #include "GUIWindow.h" #include "MusicInfoTag.h" +namespace ADDON +{ + class CVisualisation; +} + class CGUIWindowVisualisation : public CGUIWindow { public: CGUIWindowVisualisation(void); - virtual ~CGUIWindowVisualisation(void); virtual bool OnMessage(CGUIMessage& message); + virtual void OnWindowLoaded(); virtual bool OnAction(const CAction &action); virtual void FrameMove(); protected: + bool UpdateTrack(); virtual bool OnMouseEvent(const CPoint &point, const CMouseEvent &event); unsigned int m_initTimer; unsigned int m_lockedTimer; bool m_bShowPreset; + boost::shared_ptr<ADDON::CVisualisation> m_addon; MUSIC_INFO::CMusicInfoTag m_tag; // current tag info, for finding when the info manager updates }; diff --git a/xbmc/GUIWindowWeather.cpp b/xbmc/GUIWindowWeather.cpp index 3825370992..a81033232d 100644 --- a/xbmc/GUIWindowWeather.cpp +++ b/xbmc/GUIWindowWeather.cpp @@ -30,6 +30,10 @@ #include "lib/libPython/XBPython.h" #include "LangInfo.h" #include "utils/log.h" +#include "Settings.h" +#include "utils/AddonManager.h" + +using namespace ADDON; #define CONTROL_BTNREFRESH 2 #define CONTROL_SELECTLOCATION 3 @@ -56,7 +60,7 @@ #define LOCALIZED_TOKEN_FIRSTID 370 #define LOCALIZED_TOKEN_LASTID 395 -unsigned int timeToCallPlugin = 1000; +unsigned int timeToCallScript = 1000; /* FIXME'S >strings are not centered @@ -99,9 +103,9 @@ bool CGUIWindowWeather::OnMessage(CGUIMessage& message) } else if (iControl == CONTROL_SELECTLOCATION) { - // stop the plugin timer here, so the user has a full second - if (m_pluginTimer.IsRunning()) - m_pluginTimer.Stop(); + // stop the script timer here, so the user has a full second + if (m_scriptTimer.IsRunning()) + m_scriptTimer.Stop(); CGUIMessage msg(GUI_MSG_ITEM_SELECTED,GetID(),CONTROL_SELECTLOCATION); g_windowManager.SendMessage(msg); @@ -132,11 +136,11 @@ bool CGUIWindowWeather::OnMessage(CGUIMessage& message) SetProperties(); if (g_windowManager.GetActiveWindow() == WINDOW_WEATHER) { - if (!g_guiSettings.GetString("weather.plugin").IsEmpty()) - m_pluginTimer.StartZero(); + if (!g_guiSettings.GetString("weather.script").IsEmpty()) + m_scriptTimer.StartZero(); } else - CallPlugin(); + CallScript(); } break; } @@ -234,11 +238,11 @@ void CGUIWindowWeather::FrameMove() // update our controls UpdateButtons(); - // call weather plugin - if (m_pluginTimer.IsRunning() && m_pluginTimer.GetElapsedMilliseconds() > timeToCallPlugin) + // call weather script + if (m_scriptTimer.IsRunning() && m_scriptTimer.GetElapsedMilliseconds() > timeToCallScript) { - m_pluginTimer.Stop(); - CallPlugin(); + m_scriptTimer.Stop(); + CallScript(); } CGUIWindow::FrameMove(); @@ -289,26 +293,30 @@ void CGUIWindowWeather::SetProperties() } } -void CGUIWindowWeather::CallPlugin() +void CGUIWindowWeather::CallScript() { #ifdef HAS_PYTHON - if (!g_guiSettings.GetString("weather.plugin").IsEmpty()) + if (!g_guiSettings.GetString("weather.script").IsEmpty()) { - // create the full path to the plugin - CStdString plugin = "special://home/plugins/weather/" + g_guiSettings.GetString("weather.plugin") + "/default.py"; + AddonPtr addon; + if (!ADDON::CAddonMgr::Get()->GetAddon(ADDON_SCRIPT, g_guiSettings.GetString("weather.script"), addon)) + return; + + // create the full path to the script + CStdString script = addon->Path() + addon->LibName(); // initialize our sys.argv variables unsigned int argc = 2; char ** argv = new char*[argc]; - argv[0] = (char*)plugin.c_str(); + argv[0] = (char*)script.c_str(); - // if plugin is running we wait for another timeout only when in weather window + // if script is running we wait for another timeout only when in weather window if (g_windowManager.GetActiveWindow() == WINDOW_WEATHER) { int id = g_pythonParser.getScriptId(argv[0]); if (id != -1 && g_pythonParser.isRunning(id)) { - m_pluginTimer.StartZero(); + m_scriptTimer.StartZero(); return; } } @@ -319,10 +327,10 @@ void CGUIWindowWeather::CallPlugin() const CStdString &areacode = CWeather::GetAreaCode(g_guiSettings.GetString(strSetting)); argv[1] = (char*)areacode.c_str(); - // call our plugin, passing the areacode + // call our script, passing the areacode g_pythonParser.evalFile(argv[0], argc, (const char**)argv); - CLog::Log(LOGDEBUG, "%s - Weather plugin called: %s (%s)", __FUNCTION__, argv[0], argv[1]); + CLog::Log(LOGDEBUG, "%s - Weather script called: %s (%s)", __FUNCTION__, argv[0], argv[1]); } #endif } diff --git a/xbmc/GUIWindowWeather.h b/xbmc/GUIWindowWeather.h index e7752c4a91..acf83f24e6 100644 --- a/xbmc/GUIWindowWeather.h +++ b/xbmc/GUIWindowWeather.h @@ -39,10 +39,10 @@ protected: void UpdateButtons(); void UpdateLocations(); void SetProperties(); - void CallPlugin(); + void CallScript(); void Refresh(); unsigned int m_iCurWeather; - CStopWatch m_pluginTimer; + CStopWatch m_scriptTimer; }; diff --git a/xbmc/Makefile.in b/xbmc/Makefile.in index e2bce3e1dd..2f491daf59 100644 --- a/xbmc/Makefile.in +++ b/xbmc/Makefile.in @@ -19,10 +19,12 @@ INCLUDES+=-I../lib/jsoncpp/jsoncpp/include SRCS=Application.cpp \ CueDocument.cpp \ GUISettings.cpp \ + GUIWindowAddonBrowser.cpp \ GUIWindowSettings.cpp \ GUIWindowSettingsCategory.cpp \ GUIWindowSettingsProfile.cpp \ GUIWindowSettingsScreenCalibration.cpp \ + Scraper.cpp \ Settings.cpp \ SettingsControls.cpp \ GUIDialogMusicScan.cpp \ @@ -116,6 +118,7 @@ SRCS=Application.cpp \ Song.cpp \ VideoDatabase.cpp \ ViewDatabase.cpp \ + GUIDialogAddonSettings.cpp \ GUIDialogAudioSubtitleSettings.cpp \ GUIDialogBoxBase.cpp \ GUIDialogButtonMenu.cpp \ @@ -143,7 +146,6 @@ SRCS=Application.cpp \ GUIDialogVideoBookmarks.cpp \ GUIDialogVideoSettings.cpp \ GUIDialogVisualisationPresetList.cpp \ - GUIDialogVisualisationSettings.cpp \ GUIDialogVolumeBar.cpp \ GUIDialogSlider.cpp \ GUIDialogYesNo.cpp \ @@ -187,10 +189,7 @@ SRCS=Application.cpp \ GUILargeTextureManager.cpp \ GUIDialogKaiToast.cpp \ KeyboardLayoutConfiguration.cpp \ - GUIDialogPluginSettings.cpp \ - PluginSettings.cpp \ GUIDialogAccessPoints.cpp \ - ScraperSettings.cpp \ Artist.cpp \ Album.cpp \ MediaSource.cpp \ @@ -205,7 +204,6 @@ SRCS=Application.cpp \ ZeroconfBrowser.cpp \ VideoReferenceClock.cpp \ DPMSSupport.cpp \ - ScriptSettings.cpp \ GUIWindowTestPatternGL.cpp \ RenderSystem.cpp \ RenderSystemGL.cpp \ diff --git a/xbmc/MediaSource.cpp b/xbmc/MediaSource.cpp index 2638335a6a..0ee52124cc 100644 --- a/xbmc/MediaSource.cpp +++ b/xbmc/MediaSource.cpp @@ -91,6 +91,25 @@ bool CMediaSource::operator==(const CMediaSource &share) const return true; } +void AddOrReplace(VECSOURCES& sources, const VECSOURCES& extras) +{ + unsigned int i; + for( i=0;i<extras.size();++i ) + { + unsigned int j; + for ( j=0;j<sources.size();++j) + { + if (sources[j].strPath.Equals(extras[i].strPath)) + { + sources[j] = extras[i]; + break; + } + } + if (j == sources.size()) + sources.push_back(extras[i]); + } +} + void AddOrReplace(VECSOURCES& sources, const CMediaSource& source) { unsigned int i; diff --git a/xbmc/MediaSource.h b/xbmc/MediaSource.h index 567f1b8ed5..c595b3d3fd 100644 --- a/xbmc/MediaSource.h +++ b/xbmc/MediaSource.h @@ -114,4 +114,5 @@ typedef std::vector<CMediaSource> VECSOURCES; */ typedef std::vector<CMediaSource>::iterator IVECSOURCES; +void AddOrReplace(VECSOURCES& sources, const VECSOURCES& extras); void AddOrReplace(VECSOURCES& sources, const CMediaSource& source); diff --git a/xbmc/MusicDatabase.cpp b/xbmc/MusicDatabase.cpp index 37470cde8b..6b29e3b63d 100644 --- a/xbmc/MusicDatabase.cpp +++ b/xbmc/MusicDatabase.cpp @@ -30,7 +30,9 @@ #include "GUIDialogMusicScan.h" #include "utils/GUIInfoManager.h" #include "MusicInfoTag.h" -#include "ScraperSettings.h" +#include "AddonManager.h" +#include "Scraper.h" +#include "Addon.h" #include "Util.h" #include "Artist.h" #include "Album.h" @@ -59,6 +61,7 @@ using namespace std; using namespace AUTOPTR; using namespace XFILE; using namespace MUSICDATABASEDIRECTORY; +using ADDON::AddonPtr; #define RECENTLY_PLAYED_LIMIT 25 #define MIN_FULL_SEARCH_LENGTH 3 @@ -4006,7 +4009,7 @@ bool CMusicDatabase::CommitTransaction() return false; } -bool CMusicDatabase::SetScraperForPath(const CStdString& strPath, const SScraperInfo& info) +bool CMusicDatabase::SetScraperForPath(const CStdString& strPath, const ADDON::ScraperPtr& scraper) { try { @@ -4018,7 +4021,8 @@ bool CMusicDatabase::SetScraperForPath(const CStdString& strPath, const SScraper m_pDS->exec(strSQL.c_str()); // insert new settings - strSQL = FormatSQL("insert into content (strPath, strScraperPath, strContent, strSettings) values ('%s','%s','%s','%s')",strPath.c_str(),info.strPath.c_str(),info.strContent.c_str(),info.settings.GetSettings().c_str()); + strSQL = FormatSQL("insert into content (strPath, strScraperPath, strContent, strSettings) values ('%s','%s','%s','%s')", + strPath.c_str(), scraper->Parent()->UUID().c_str(), ADDON::TranslateContent(scraper->Content()).c_str(), scraper->GetSettings().c_str()); m_pDS->exec(strSQL.c_str()); return true; @@ -4030,7 +4034,7 @@ bool CMusicDatabase::SetScraperForPath(const CStdString& strPath, const SScraper return false; } -bool CMusicDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& info) +bool CMusicDatabase::GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& info) { try { @@ -4071,41 +4075,51 @@ bool CMusicDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& } if (!m_pDS->eof()) - { - info.strContent = m_pDS->fv("content.strContent").get_asString(); - info.strPath = m_pDS->fv("content.strScraperPath").get_asString(); - info.settings.LoadUserXML(m_pDS->fv("content.strSettings").get_asString()); - - CScraperParser parser; - parser.Load("special://xbmc/system/scrapers/music/" + info.strPath); - info.strTitle = parser.GetName(); - info.strDate = parser.GetDate(); - info.strFramework = parser.GetFramework(); - info.strLanguage = parser.GetLanguage(); + { // try and ascertain scraper for this path + CONTENT_TYPE content = ADDON::TranslateContent(m_pDS->fv("content.strContent").get_asString()); + CStdString scraperUUID = m_pDS->fv("content.strScraperPath").get_asString(); + + if (content != CONTENT_NONE) + { // content set, use pre configured or default scraper + ADDON::AddonPtr addon; + if (!scraperUUID.empty() && ADDON::CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRAPER, scraperUUID, addon) && addon) + { + info = boost::dynamic_pointer_cast<ADDON::CScraper>(addon->Clone(addon)); + if (!info) + return false; + } - } - if (info.strPath.IsEmpty()) - { // no info available yet - check for a fallback - if (!strPath.Equals("musicdb://")) // default fallback - GetScraperForPath("musicdb://",info); + // store this path's settings + info->m_pathContent = content; + info->LoadUserXML(m_pDS->fv("content.strSettings").get_asString()); + } else - { // none available yet (user wisely left defaults as is and didn't touch 'em) - CScraperParser parser; - if (parser.Load("special://xbmc/system/scrapers/music/" + g_guiSettings.GetString("musiclibrary.scraper"))) + { // use default scraper for this content type + ADDON::AddonPtr defaultScraper; + if (ADDON::CAddonMgr::Get()->GetDefault(ADDON::ADDON_SCRAPER, defaultScraper, content)) { - info.strPath = g_guiSettings.GetString("musiclibrary.scraper"); - info.strContent = "albums"; - info.strTitle = parser.GetName(); - info.strDate = parser.GetDate(); - info.strFramework = parser.GetFramework(); - info.strLanguage = parser.GetLanguage(); - info.settings.LoadSettingsXML("special://xbmc/system/scrapers/music/" + info.strPath); - SetScraperForPath("musicdb://",info); + info = boost::dynamic_pointer_cast<ADDON::CScraper>(defaultScraper->Clone(defaultScraper)); + if (info) + { + info->m_pathContent = content; + } } } } - m_pDS->close(); + + if (!info) + { // use default music scraper instead + ADDON::AddonPtr addon; + if(ADDON::CAddonMgr::Get()->GetDefault(ADDON::ADDON_SCRAPER, addon, CONTENT_ALBUMS)) + { + info = boost::dynamic_pointer_cast<ADDON::CScraper>(addon); + return (info); + } + else + return false; + } + return true; } catch (...) diff --git a/xbmc/MusicDatabase.h b/xbmc/MusicDatabase.h index 44ff9b4107..6c64821c91 100644 --- a/xbmc/MusicDatabase.h +++ b/xbmc/MusicDatabase.h @@ -25,8 +25,7 @@ #pragma once #include "Database.h" #include "Album.h" - -struct SScraperInfo; +#include "Scraper.h" class CArtist; class CFileItem; @@ -189,8 +188,8 @@ public: int GetVariousArtistsAlbumsCount(); bool SetSongRating(const CStdString &filePath, char rating); - bool SetScraperForPath(const CStdString& strPath, const SScraperInfo& info); - bool GetScraperForPath(const CStdString& strPath, SScraperInfo& info); + bool SetScraperForPath(const CStdString& strPath, const ADDON::ScraperPtr& info); + bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& info); void ExportToXML(const CStdString &xmlFile, bool singleFiles = false, bool images=false, bool overwrite=false); void ImportFromXML(const CStdString &xmlFile); diff --git a/xbmc/MusicInfoScanner.cpp b/xbmc/MusicInfoScanner.cpp index 13a9a751db..7898a10e2e 100644 --- a/xbmc/MusicInfoScanner.cpp +++ b/xbmc/MusicInfoScanner.cpp @@ -807,7 +807,7 @@ bool CMusicInfoScanner::DownloadAlbumInfo(const CStdString& strPath, const CStdS return true; // find album info - SScraperInfo info; + ADDON::ScraperPtr info; if (!m_musicDatabase.GetScraperForPath(strPath,info)) { m_musicDatabase.Close(); @@ -831,7 +831,7 @@ bool CMusicInfoScanner::DownloadAlbumInfo(const CStdString& strPath, const CStdS if (XFILE::CFile::Exists(strNfo)) { CLog::Log(LOGDEBUG,"Found matching nfo file: %s", strNfo.c_str()); - result = nfoReader.Create(strNfo,"albums"); + result = nfoReader.Create(strNfo, info); if (result == CNfoFile::FULL_NFO) { CLog::Log(LOGDEBUG, "%s Got details from nfo", __FUNCTION__); @@ -846,9 +846,9 @@ bool CMusicInfoScanner::DownloadAlbumInfo(const CStdString& strPath, const CStdS { CScraperUrl scrUrl(nfoReader.m_strImDbUrl); CMusicAlbumInfo album("nfo",scrUrl); - CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",nfoReader.m_strScraper.c_str()); + info = nfoReader.GetScraperInfo(); + CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",info->Name().c_str()); CLog::Log(LOGDEBUG,"-- nfo url: %s", scrUrl.m_url[0].m_url.c_str()); - info.strPath = nfoReader.m_strScraper; scraper.SetScraperInfo(info); scraper.GetAlbums().push_back(album); } @@ -1035,7 +1035,7 @@ bool CMusicInfoScanner::DownloadArtistInfo(const CStdString& strPath, const CStd return true; // find artist info - SScraperInfo info; + ADDON::ScraperPtr info; if (!m_musicDatabase.GetScraperForPath(strPath,info)) { m_musicDatabase.Close(); @@ -1058,7 +1058,7 @@ bool CMusicInfoScanner::DownloadArtistInfo(const CStdString& strPath, const CStd if (XFILE::CFile::Exists(strNfo)) { CLog::Log(LOGDEBUG,"Found matching nfo file: %s", strNfo.c_str()); - result = nfoReader.Create(strNfo,"albums"); + result = nfoReader.Create(strNfo, info); if (result == CNfoFile::FULL_NFO) { CLog::Log(LOGDEBUG, "%s Got details from nfo", __FUNCTION__); @@ -1073,9 +1073,9 @@ bool CMusicInfoScanner::DownloadArtistInfo(const CStdString& strPath, const CStd { CScraperUrl scrUrl(nfoReader.m_strImDbUrl); CMusicArtistInfo artist("nfo",scrUrl); - CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",nfoReader.m_strScraper.c_str()); + info = nfoReader.GetScraperInfo(); + CLog::Log(LOGDEBUG,"-- nfo-scraper: %s",info->Name().c_str()); CLog::Log(LOGDEBUG,"-- nfo url: %s", scrUrl.m_url[0].m_url.c_str()); - info.strPath = nfoReader.m_strScraper; scraper.SetScraperInfo(info); scraper.GetArtists().push_back(artist); } diff --git a/xbmc/NfoFile.cpp b/xbmc/NfoFile.cpp index 6395a60f69..a5f57bbd15 100644 --- a/xbmc/NfoFile.cpp +++ b/xbmc/NfoFile.cpp @@ -25,8 +25,10 @@ #include "NfoFile.h" #include "VideoDatabase.h" #include "utils/IMDB.h" +#include "utils/AddonManager.h" #include "FileSystem/File.h" #include "FileSystem/Directory.h" +#include "GUISettings.h" #include "Util.h" #include "FileItem.h" #include "Album.h" @@ -38,6 +40,8 @@ using namespace XFILE; using namespace std; +using namespace ADDON; + ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// @@ -53,45 +57,39 @@ CNfoFile::~CNfoFile() Close(); } -CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, const CStdString& strContent, int episode) -{ - SScraperInfo info; - info.strContent = strContent; - return Create(strPath, info, episode); -} - -CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, SScraperInfo& info, int episode) +CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, ScraperPtr& info, int episode) { m_info = info; // assume we can use these settings - m_strContent = info.strContent; + m_content = info->Content(); if (FAILED(Load(strPath))) return NO_NFO; CFileItemList items; - CStdString strScraperBasePath, strDefault, strSelected; bool bNfo=false; - if (m_strContent.Equals("albums")) + + AddonPtr addon; + ScraperPtr defaultScraper; + if (!CAddonMgr::Get()->GetDefault(ADDON_SCRAPER, addon, m_content)) + return NO_NFO; + else + defaultScraper = boost::dynamic_pointer_cast<CScraper>(addon); + + if (m_content == CONTENT_ALBUMS) { CAlbum album; bNfo = GetDetails(album); - CDirectory::GetDirectory("special://xbmc/system/scrapers/music/",items,".xml",false); - strScraperBasePath = "special://xbmc/system/scrapers/music/"; - CUtil::AddFileToFolder(strScraperBasePath, g_guiSettings.GetString("musiclibrary.scraper"), strDefault); } - else if (m_strContent.Equals("artists")) + else if (m_content == CONTENT_ARTISTS) { CArtist artist; bNfo = GetDetails(artist); - CDirectory::GetDirectory("special://xbmc/system/scrapers/music/",items,".xml",false); - strScraperBasePath = "special://xbmc/system/scrapers/music/"; - CUtil::AddFileToFolder(strScraperBasePath, g_guiSettings.GetString("musiclibrary.scraper"), strDefault); } - else if (m_strContent.Equals("tvshows") || m_strContent.Equals("movies") || m_strContent.Equals("musicvideos")) + else if (m_content == CONTENT_TVSHOWS || m_content == CONTENT_MOVIES || m_content == CONTENT_MUSICVIDEOS) { // first check if it's an XML file with the info we need CVideoInfoTag details; bNfo = GetDetails(details); - if (episode > -1 && bNfo && m_strContent.Equals("tvshows")) + if (episode > -1 && bNfo && m_content == CONTENT_TVSHOWS) { int infos=0; while (m_headofdoc && details.m_iEpisode != episode) @@ -109,45 +107,36 @@ CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, SScraperInfo& in bNfo = GetDetails(details); } } - CStdString strURL = details.m_strEpisodeGuide; - strScraperBasePath = "special://xbmc/system/scrapers/video/"; - CDirectory::GetDirectory("special://xbmc/system/scrapers/video/",items,".xml",false); - - if (m_strContent.Equals("movies")) - CUtil::AddFileToFolder(strScraperBasePath, g_guiSettings.GetString("scrapers.moviedefault"), strDefault); - else if (m_strContent.Equals("tvshows")) - CUtil::AddFileToFolder(strScraperBasePath, g_guiSettings.GetString("scrapers.tvshowdefault"), strDefault); - else if (m_strContent.Equals("musicvideos")) - CUtil::AddFileToFolder(strScraperBasePath, g_guiSettings.GetString("scrapers.musicvideodefault"), strDefault); } // Get Selected Scraper CVideoDatabase database; + ADDON::ScraperPtr selected; database.Open(); - database.GetScraperForPath(strPath,info); + database.GetScraperForPath(strPath,selected); database.Close(); - CUtil::AddFileToFolder(strScraperBasePath, info.strPath, strSelected); - vector<CStdString> vecScrapers; + vector<ScraperPtr> vecScrapers; // add selected scraper - vecScrapers.push_back(strSelected); + if (selected) + vecScrapers.push_back(selected); - if (g_guiSettings.GetBool("scrapers.langfallback")) + /*if (g_guiSettings.GetBool("scrapers.langfallback")) { - for (int i=0;i<items.Size();++i) + for (unsigned i=0;i<addons.size();++i) { - if (!items[i]->m_bIsFolder) - { - // skip selected and default scraper - if (items[i]->m_strPath.Equals(strSelected) || items[i]->m_strPath.Equals(strDefault)) - continue; + // skip selected and default scraper + if (addons[i]->UUID().Equals(selected->Parent()) || addons[i]->UUID().Equals(defaultScraper->UUID())) + continue; + + (CScraperParser parser2; + parser2.Load(addons[i]); + CONTENT_TYPE content = parser2.GetContent(); - SScraperInfo info2; - CScraperParser parser2; - parser2.Load(items[i]->m_strPath); - info2.strContent = parser2.GetContent(); - info2.strLanguage = parser2.GetLanguage(); + // skip if scraper requires settings and there's nothing set yet + if (parser2.RequiresSettings() && info2.settings.GetSettings().IsEmpty()) + continue; // skip if scraper requires settings and there's nothing set yet if (parser2.RequiresSettings() && info2.settings.GetSettings().IsEmpty()) @@ -157,16 +146,14 @@ CNfoFile::NFOResult CNfoFile::Create(const CStdString& strPath, SScraperInfo& in if (info.strContent != info2.strContent && (info.strContent.Equals("movies") || info.strContent.Equals("tvshows") || info.strContent.Equals("musicvideos"))) continue; - // add same language, multi-language and music scrapers - if (info.strLanguage == info2.strLanguage || info2.strLanguage == "multi" || info.strContent.Equals("albums") || info.strContent.Equals("artists")) - vecScrapers.push_back(items[i]->m_strPath); - } + // add same language, multi-language and music scrapers + // TODO addons language handling } - } + }*/ // add default scraper - if (find(vecScrapers.begin(),vecScrapers.end(),strDefault) == vecScrapers.end()) - vecScrapers.push_back(strDefault); + if ((selected && selected->Parent() != defaultScraper) || !selected) + vecScrapers.push_back(defaultScraper); // search .. int res = -1; @@ -201,7 +188,7 @@ bool CNfoFile::DoScrape(CScraperParser& parser, const CScraperUrl* pURL, const C parser.m_param[i] = strHTML[i]; } - m_strImDbUrl = parser.Parse(strFunction, m_strScraper.CompareNoCase(m_info.strPath) == 0 ? &m_info.settings : 0); + m_strImDbUrl = parser.Parse(strFunction); TiXmlDocument doc; doc.Parse(m_strImDbUrl.c_str()); @@ -231,27 +218,25 @@ bool CNfoFile::DoScrape(CScraperParser& parser, const CScraperUrl* pURL, const C return true; } -int CNfoFile::Scrape(const CStdString& strScraperPath, const CStdString& strURL /* = "" */) +int CNfoFile::Scrape(const ScraperPtr& scraper, const CStdString& strURL /* = "" */) { - CScraperParser m_parser; - if (!m_parser.Load(strScraperPath)) + CScraperParser parser; + if (!parser.Load(scraper)) return 0; - if (m_parser.GetContent() != m_strContent && - !(m_strContent.Equals("artists") && m_parser.GetContent().Equals("albums"))) + if (scraper->Supports(m_content) && + !(m_content == CONTENT_ARTISTS && scraper->Content() == CONTENT_ALBUMS)) // artists are scraped by album content scrapers { return 1; } - m_strScraper = CUtil::GetFileName(strScraperPath); - // init and clear cache - m_parser.ClearCache(); + parser.ClearCache(); if (strURL.IsEmpty()) { - m_parser.m_param[0] = m_doc; - m_strImDbUrl = m_parser.Parse("NfoScrape", m_strScraper.CompareNoCase(m_info.strPath) == 0 ? &m_info.settings : 0); + parser.m_param[0] = m_doc; + m_strImDbUrl = parser.Parse("NfoScrape"); TiXmlDocument doc; doc.Parse(m_strImDbUrl.c_str()); if (doc.RootElement() && doc.RootElement()->FirstChildElement()) @@ -268,7 +253,7 @@ int CNfoFile::Scrape(const CStdString& strScraperPath, const CStdString& strURL } } - if (!DoScrape(m_parser)) + if (!DoScrape(parser)) return 2; if (m_strImDbUrl.size() > 0) @@ -278,8 +263,8 @@ int CNfoFile::Scrape(const CStdString& strScraperPath, const CStdString& strURL } else // we check to identify the episodeguide url { - m_parser.m_param[0] = strURL; - CStdString strEpGuide = m_parser.Parse("EpisodeGuideUrl", m_strScraper.CompareNoCase(m_info.strPath) == 0 ? &m_info.settings : 0); // allow corrections? + parser.m_param[0] = strURL; + CStdString strEpGuide = parser.Parse("EpisodeGuideUrl"); // allow corrections? if (strEpGuide.IsEmpty()) return 1; return 0; diff --git a/xbmc/NfoFile.h b/xbmc/NfoFile.h index f3e3869fc5..d2413160ec 100644 --- a/xbmc/NfoFile.h +++ b/xbmc/NfoFile.h @@ -30,7 +30,7 @@ #endif // _MSC_VER > 1000 #include "tinyXML/tinyxml.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "utils/CharsetConverter.h" class CVideoInfoTag; @@ -51,8 +51,7 @@ public: ERROR_NFO = 4 }; - NFOResult Create(const CStdString&,const CStdString&, int episode=-1); - NFOResult Create(const CStdString&,SScraperInfo&, int episode=-1); + NFOResult Create(const CStdString&, ADDON::ScraperPtr&, int episode=-1); template<class T> bool GetDetails(T& details,const char* document=NULL) { @@ -70,21 +69,20 @@ public: return details.Load(doc.RootElement(),true); } - CStdString m_strScraper; CStdString m_strImDbUrl; CStdString m_strImDbNr; void Close(); - void SetScraperInfo(const SScraperInfo& info) { m_info.Reset(); m_info = info; } - const SScraperInfo& GetScraperInfo() const { return m_info; } + void SetScraperInfo(const ADDON::ScraperPtr& info) { m_info = info; } + const ADDON::ScraperPtr& GetScraperInfo() const { return m_info; } private: int Load(const CStdString&); - int Scrape(const CStdString&, const CStdString& strURL=""); + int Scrape(const ADDON::ScraperPtr& scraper, const CStdString& strURL=""); private: char* m_doc; char* m_headofdoc; int m_size; - SScraperInfo m_info; - CStdString m_strContent; + ADDON::ScraperPtr m_info; + CONTENT_TYPE m_content; bool DoScrape(CScraperParser& parser, const CScraperUrl* pURL=NULL, const CStdString& strFunction="NfoUrl"); }; diff --git a/xbmc/PluginSettings.cpp b/xbmc/PluginSettings.cpp deleted file mode 100644 index e158bd14be..0000000000 --- a/xbmc/PluginSettings.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "PluginSettings.h" -#include "Util.h" -#include "FileSystem/File.h" -#include "FileSystem/Directory.h" -#include "utils/log.h" - -CBasicSettings::CBasicSettings() -{ -} - -CBasicSettings::~CBasicSettings() -{ -} - -bool CBasicSettings::SaveFromDefault(void) -{ - if (!GetPluginRoot()) //if scraper has no settings return false - return false; - - TiXmlElement *setting = GetPluginRoot()->FirstChildElement("setting"); - while (setting) - { - CStdString id; - if (setting->Attribute("id")) - id = setting->Attribute("id"); - CStdString value; - if (setting->Attribute("default")) - value = setting->Attribute("default"); - Set(id,value); - setting = setting->NextSiblingElement("setting"); - } - return true; -} - -void CBasicSettings::Clear() -{ - m_pluginXmlDoc.Clear(); - m_userXmlDoc.Clear(); -} - -void CBasicSettings::Set(const CStdString& key, const CStdString& value) -{ - if (key == "") return; - - // Try to find the setting and change its value - if (!m_userXmlDoc.RootElement()) - { - TiXmlElement node("settings"); - m_userXmlDoc.InsertEndChild(node); - } - TiXmlElement *setting = m_userXmlDoc.RootElement()->FirstChildElement("setting"); - while (setting) - { - const char *id = setting->Attribute("id"); - if (id && strcmpi(id, key) == 0) - { - setting->SetAttribute("value", value.c_str()); - return; - } - - setting = setting->NextSiblingElement("setting"); - } - - // Setting not found, add it - TiXmlElement nodeSetting("setting"); - nodeSetting.SetAttribute("id", key.c_str()); - nodeSetting.SetAttribute("value", value.c_str()); - m_userXmlDoc.RootElement()->InsertEndChild(nodeSetting); -} - -CStdString CBasicSettings::Get(const CStdString& key) const -{ - if (m_userXmlDoc.RootElement()) - { - // Try to find the setting and return its value - const TiXmlElement *setting = m_userXmlDoc.RootElement()->FirstChildElement("setting"); - while (setting) - { - const char *id = setting->Attribute("id"); - if (id && strcmpi(id, key) == 0) - return setting->Attribute("value"); - - setting = setting->NextSiblingElement("setting"); - } - } - - if (m_pluginXmlDoc.RootElement()) - { - // Try to find the setting in the plugin and return its default value - const TiXmlElement* setting = m_pluginXmlDoc.RootElement()->FirstChildElement("setting"); - while (setting) - { - const char *id = setting->Attribute("id"); - if (id && strcmpi(id, key) == 0 && setting->Attribute("default")) - return setting->Attribute("default"); - - setting = setting->NextSiblingElement("setting"); - } - } - - // Otherwise return empty string - return ""; -} - -CPluginSettings::CPluginSettings() -{ -} - -CPluginSettings::~CPluginSettings() -{ -} - -bool CPluginSettings::Load(const CURL& url) -{ - m_url = url; - - // create the users filepath - m_userFileName.Format("special://profile/plugin_data/%s/%s", url.GetHostName().c_str(), url.GetFileName().c_str()); - CUtil::RemoveSlashAtEnd(m_userFileName); - CUtil::AddFileToFolder(m_userFileName, "settings.xml", m_userFileName); - - // Create our final path - CStdString pluginFileName = "special://home/plugins/"; - - CUtil::AddFileToFolder(pluginFileName, url.GetHostName(), pluginFileName); - CUtil::AddFileToFolder(pluginFileName, url.GetFileName(), pluginFileName); - - CUtil::AddFileToFolder(pluginFileName, "resources", pluginFileName); - CUtil::AddFileToFolder(pluginFileName, "settings.xml", pluginFileName); - - if (!m_pluginXmlDoc.LoadFile(pluginFileName)) - { - CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", pluginFileName.c_str(), m_pluginXmlDoc.ErrorRow(), m_pluginXmlDoc.ErrorDesc()); - return false; - } - - // Make sure that the plugin XML has the settings element - TiXmlElement *setting = m_pluginXmlDoc.RootElement(); - if (!setting || strcmpi(setting->Value(), "settings") != 0) - { - CLog::Log(LOGERROR, "Error loading Settings %s: cannot find root element 'settings'", pluginFileName.c_str()); - return false; - } - - // Load the user saved settings. If it does not exist, create it - if (!m_userXmlDoc.LoadFile(m_userFileName)) - { - TiXmlDocument doc; - TiXmlDeclaration decl("1.0", "UTF-8", "yes"); - doc.InsertEndChild(decl); - - TiXmlElement xmlRootElement("settings"); - doc.InsertEndChild(xmlRootElement); - - m_userXmlDoc = doc; - - // Don't worry about the actual settings, they will be set when the user clicks "Ok" - // in the settings dialog - } - - return true; -} - -bool CPluginSettings::Save(void) -{ - // break down the path into directories - CStdString strRoot, strType, strPlugin; - CUtil::GetDirectory(m_userFileName, strPlugin); - CUtil::RemoveSlashAtEnd(strPlugin); - CUtil::GetDirectory(strPlugin, strType); - CUtil::RemoveSlashAtEnd(strType); - CUtil::GetDirectory(strType, strRoot); - CUtil::RemoveSlashAtEnd(strRoot); - - // create the individual folders - if (!XFILE::CDirectory::Exists(strRoot)) - XFILE::CDirectory::Create(strRoot); - if (!XFILE::CDirectory::Exists(strType)) - XFILE::CDirectory::Create(strType); - if (!XFILE::CDirectory::Exists(strPlugin)) - XFILE::CDirectory::Create(strPlugin); - - return m_userXmlDoc.SaveFile(m_userFileName); -} - -TiXmlElement* CBasicSettings::GetPluginRoot() -{ - return m_pluginXmlDoc.RootElement(); -} - -bool CPluginSettings::SettingsExist(const CStdString& strPath) -{ - CURL url(strPath); - CStdString pluginFileName = "special://home/plugins/"; - - // Create our final path - CUtil::AddFileToFolder(pluginFileName, url.GetHostName(), pluginFileName); - CUtil::AddFileToFolder(pluginFileName, url.GetFileName(), pluginFileName); - - CUtil::AddFileToFolder(pluginFileName, "resources", pluginFileName); - CUtil::AddFileToFolder(pluginFileName, "settings.xml", pluginFileName); - - // Load the settings file to verify it's valid - TiXmlDocument xmlDoc; - if (!xmlDoc.LoadFile(pluginFileName)) - return false; - - // Make sure that the plugin XML has the settings element - TiXmlElement *setting = xmlDoc.RootElement(); - if (!setting || strcmpi(setting->Value(), "settings") != 0) - return false; - - return true; -} - -CPluginSettings& CPluginSettings::operator=(const CBasicSettings& settings) -{ - *((CBasicSettings*)this) = settings; - - return *this; -} - -CPluginSettings g_currentPluginSettings; diff --git a/xbmc/PluginSettings.h b/xbmc/PluginSettings.h deleted file mode 100644 index 53d6226b8a..0000000000 --- a/xbmc/PluginSettings.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef PLUGINSETTINGS_H_ -#define PLUGINSETTINGS_H_ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "tinyXML/tinyxml.h" -#include "URL.h" - -class CBasicSettings -{ -public: - CBasicSettings(); - virtual ~CBasicSettings(); - - bool SaveFromDefault(void); - virtual bool Load(const CURL& url) { return false; } - virtual bool Save(void) { return false; } - void Clear(); - - void Set(const CStdString& key, const CStdString& value); - CStdString Get(const CStdString& key) const; - - TiXmlElement* GetPluginRoot(); -protected: - TiXmlDocument m_userXmlDoc; - TiXmlDocument m_pluginXmlDoc; -}; - -class CPluginSettings : public CBasicSettings -{ -public: - CPluginSettings(); - virtual ~CPluginSettings(); - bool Load(const CURL& url); - bool Save(void); - static bool SettingsExist(const CStdString &strPath); - - CPluginSettings& operator =(const CBasicSettings&); -private: - CStdString m_id; - CURL m_url; - CStdString m_userFileName; -}; - -extern CPluginSettings g_currentPluginSettings; - -#endif diff --git a/xbmc/PowerManager.cpp b/xbmc/PowerManager.cpp index 09700883d8..4d62b6037d 100644 --- a/xbmc/PowerManager.cpp +++ b/xbmc/PowerManager.cpp @@ -47,11 +47,11 @@ extern HWND g_hWnd; #ifdef HAS_LIRC #include "common/LIRC.h" #endif -#ifdef HAS_IRSERVERSUITE
- #include "common/IRServerSuite/IRServerSuite.h"
+#ifdef HAS_IRSERVERSUITE + #include "common/IRServerSuite/IRServerSuite.h" #endif -using namespace ANNOUNCEMENT;
+using namespace ANNOUNCEMENT; CPowerManager g_powerManager; diff --git a/xbmc/Profile.cpp b/xbmc/Profile.cpp index 49e77bc712..ef9f42963f 100644 --- a/xbmc/Profile.cpp +++ b/xbmc/Profile.cpp @@ -29,12 +29,14 @@ CProfile::CProfile(void) _bCanWrite = true; _bSources = true; _bCanWriteSources = true; + _bAddons = true; _bLockPrograms = false; _bLockPictures = false; _bLockFiles = false; _bLockVideo = false; _bLockMusic = false; _bLockSettings = false; + _bLockAddonManager = false; _iLockMode = LOCK_MODE_EVERYONE; } diff --git a/xbmc/Profile.h b/xbmc/Profile.h index 9b277ab51c..68a93e755b 100644 --- a/xbmc/Profile.h +++ b/xbmc/Profile.h @@ -42,7 +42,9 @@ public: bool canWriteDatabases() const { return _bCanWrite; } bool hasSources() const { return _bSources; } bool canWriteSources() const { return _bCanWriteSources; } + bool hasAddons() const { return _bAddons; } bool settingsLocked() const { return _bLockSettings; } + bool addonmanagerLocked() const { return _bLockAddonManager; } bool musicLocked() const { return _bLockMusic; } bool videoLocked() const { return _bLockVideo; } bool picturesLocked() const { return _bLockPictures; } @@ -61,6 +63,7 @@ public: void setSources(bool bHas) { _bSources = bHas; } void setWriteSources(bool bCan) { _bCanWriteSources = bCan; } + void setAddonManagerLocked(bool bLocked) { _bLockAddonManager = bLocked; } void setSettingsLocked(bool bLocked) { _bLockSettings = bLocked; } void setFilesLocked(bool bLocked) { _bLockFiles = bLocked; } void setMusicLocked(bool bLocked) { _bLockMusic = bLocked; } @@ -76,10 +79,12 @@ public: bool _bCanWrite; bool _bSources; bool _bCanWriteSources; + bool _bAddons; // lock stuff LockType _iLockMode; CStdString _strLockCode; + bool _bLockAddonManager; bool _bLockSettings; bool _bLockMusic; bool _bLockVideo; diff --git a/xbmc/ScraperSettings.cpp b/xbmc/Scraper.cpp index 630b5406d1..d6163f4ec2 100644 --- a/xbmc/ScraperSettings.cpp +++ b/xbmc/Scraper.cpp @@ -1,47 +1,72 @@ /* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - +* Copyright (C) 2005-2008 Team XBMC +* http://www.xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* http://www.gnu.org/copyleft/gpl.html +* +*/ +#include "Scraper.h" #include "XMLUtils.h" -#include "ScraperSettings.h" #include "FileSystem/File.h" #include "FileSystem/Directory.h" #include "FileSystem/FileCurl.h" -#include "utils/CharsetConverter.h" +#include "utils/AddonManager.h" #include "utils/ScraperParser.h" #include "utils/ScraperUrl.h" +#include "utils/CharsetConverter.h" #include "utils/log.h" #include <sstream> -using namespace std; +using std::vector; +using std::stringstream; + +namespace ADDON +{ + +class CAddon; + +AddonPtr CScraper::Clone(const AddonPtr &self) const +{ + return AddonPtr(new CScraper(*this, self)); +} + +CScraper::CScraper(const CScraper &rhs, const AddonPtr &self) + : CAddon(rhs, self) +{ +} -CScraperSettings::CScraperSettings() +bool CScraper::LoadSettings() { + //TODO if cloned settings don't exist, load master settings and copy + if (!Parent()) + return CAddon::LoadUserSettings(); + else + return LoadSettingsXML(); } -CScraperSettings::~CScraperSettings() +bool CScraper::HasSettings() { + if (!m_userXmlDoc.RootElement()) + return LoadSettingsXML(); + + return true; } -bool CScraperSettings::Load(const CStdString& strSettings, const CStdString& strSaved) +bool CScraper::Load(const CStdString& strSettings, const CStdString& strSaved) { if (!LoadSettingsXML(strSettings)) return false; @@ -51,7 +76,7 @@ bool CScraperSettings::Load(const CStdString& strSettings, const CStdString& str return true; } -bool CScraperSettings::LoadUserXML(const CStdString& strSaved) +bool CScraper::LoadUserXML(const CStdString& strSaved) { m_userXmlDoc.Clear(); m_userXmlDoc.Parse(strSaved.c_str()); @@ -59,18 +84,24 @@ bool CScraperSettings::LoadUserXML(const CStdString& strSaved) return m_userXmlDoc.RootElement()?true:false; } -bool CScraperSettings::LoadSettingsXML(const CStdString& strScraper, const CStdString& strFunction, const CScraperUrl* url) +bool CScraper::LoadSettingsXML(const CStdString& strFunction, const CScraperUrl* url) { - CScraperParser parser; + CStdString uuid = UUID(); + if (Parent()) + { // called from DialogContentSettings. We are working with the cloned scraper settings + uuid = Parent()->UUID(); + } + // load our scraper xml - if (!parser.Load(strScraper)) + CScraperParser parser; + if (!parser.Load(uuid)) return false; if (!parser.HasFunction(strFunction)) return false; if (!url && strFunction.Equals("GetSettings")) // entry point - m_pluginXmlDoc.Clear(); + m_addonXmlDoc.Clear(); vector<CStdString> strHTML; if (url) @@ -110,17 +141,22 @@ bool CScraperSettings::LoadSettingsXML(const CStdString& strScraper, const CStdS } // check our document - if (!m_pluginXmlDoc.RootElement()) + if (!m_addonXmlDoc.RootElement()) { TiXmlElement xmlRootElement("settings"); - m_pluginXmlDoc.InsertEndChild(xmlRootElement); + m_addonXmlDoc.InsertEndChild(xmlRootElement); } // loop over all tags and append any setting tags TiXmlElement* pElement = doc.RootElement()->FirstChildElement("setting"); + if (pElement) + m_hasSettings = true; + else + m_hasSettings = false; + while (pElement) { - m_pluginXmlDoc.RootElement()->InsertEndChild(*pElement); + m_addonXmlDoc.RootElement()->InsertEndChild(*pElement); pElement = pElement->NextSiblingElement("setting"); } @@ -133,16 +169,16 @@ bool CScraperSettings::LoadSettingsXML(const CStdString& strScraper, const CStdS if (szFunction) { CScraperUrl scrURL(xurl); - if (!LoadSettingsXML(strScraper,szFunction,&scrURL)) + if (!LoadSettingsXML(szFunction,&scrURL)) return false; } xurl = xurl->NextSiblingElement("url"); } - return m_pluginXmlDoc.RootElement()?true:false; + return m_addonXmlDoc.RootElement()?true:false; } -CStdString CScraperSettings::GetSettings() const +CStdString CScraper::GetSettings() const { stringstream stream; if (m_userXmlDoc.RootElement()) @@ -151,3 +187,5 @@ CStdString CScraperSettings::GetSettings() const return stream.str(); } +}; /* namespace ADDON */ + diff --git a/xbmc/Scraper.h b/xbmc/Scraper.h new file mode 100644 index 0000000000..8a811c7034 --- /dev/null +++ b/xbmc/Scraper.h @@ -0,0 +1,58 @@ +#pragma once +/* + * Copyright (C) 2005-2008 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ +#include "utils/Addon.h" +#include "utils/ScraperUrl.h" + +namespace ADDON +{ + class CScraper; + typedef boost::shared_ptr<CScraper> ScraperPtr; + + class CScraper : public CAddon + { + public: + CScraper(const AddonProps &props) : CAddon(props) { } + virtual ~CScraper() {} + virtual AddonPtr Clone(const AddonPtr &self) const; + + // from CAddon + virtual bool HasSettings(); + virtual bool LoadSettings(); + + // scraper specialization + bool LoadUserXML(const CStdString& strXML); + bool LoadSettingsXML(const CStdString& strFunction="GetSettings", const CScraperUrl* url=NULL); + bool Load(const CStdString& strSettings, const CStdString& strSaved); + CStdString GetSettings() const; + CStdString m_strLanguage; + CONTENT_TYPE Content() const { return m_pathContent; } + const CStdString Framework() const { return m_framework; } + CONTENT_TYPE m_pathContent; + + private: + CScraper(const CScraper&, const AddonPtr&); + bool m_hasSettings; + CStdString m_framework; + }; + +}; /* namespace ADDON */ + diff --git a/xbmc/ScraperSettings.h b/xbmc/ScraperSettings.h deleted file mode 100644 index be8d7441d3..0000000000 --- a/xbmc/ScraperSettings.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef SCRAPERSETTINGS_H_ -#define SCRAPERSETTINGS_H_ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "PluginSettings.h" -#include "StdString.h" - -class CScraperUrl; - -class CScraperSettings : public CBasicSettings -{ -public: - CScraperSettings(); - virtual ~CScraperSettings(); - bool LoadUserXML(const CStdString& strXML); - bool LoadSettingsXML(const CStdString& strScraper, const CStdString& strFunction="GetSettings", const CScraperUrl* url=NULL); - bool Load(const CStdString& strSettings, const CStdString& strSaved); - CStdString GetSettings() const; -}; - -struct SScraperInfo -{ - CStdString strTitle; - CStdString strPath; - CStdString strThumb; - CStdString strContent; - CStdString strLanguage; - CStdString strFramework; - CStdString strDate; - CScraperSettings settings; - void Reset() - { - strTitle.clear(); - strPath.clear(); - strThumb.clear(); - strContent.clear(); - strLanguage.clear(); - settings.Clear(); - } -}; - -#endif - diff --git a/xbmc/ScriptSettings.cpp b/xbmc/ScriptSettings.cpp deleted file mode 100644 index a7a106fc3f..0000000000 --- a/xbmc/ScriptSettings.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/*
- * Copyright (C) 2005-2008 Team XBMC
- * http://www.xbmc.org
- *
- * This Program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This Program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with XBMC; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- */
-
-#include "ScriptSettings.h"
-#include "Util.h"
-#include "FileSystem/Directory.h"
-#include "utils/log.h"
-#ifdef _WIN32
-#include "PlatformDefs.h" //for strcasecmp
-#endif
-
-CScriptSettings::CScriptSettings()
-{
-}
-
-CScriptSettings::~CScriptSettings()
-{
-}
-
-bool CScriptSettings::Load(const CStdString& strPath)
-{
- m_scriptPath = strPath;
-
- // create the users filepath
- CUtil::RemoveSlashAtEnd(m_scriptPath);
- m_userFileName.Format("special://profile/script_data/%s", CUtil::GetFileName(m_scriptPath));
- CUtil::AddFileToFolder(m_userFileName, "settings.xml", m_userFileName);
-
- // Create our final settings path
- CStdString scriptFileName;
- CUtil::AddFileToFolder(m_scriptPath, "resources", scriptFileName);
- CUtil::AddFileToFolder(scriptFileName, "settings.xml", scriptFileName);
-
- if (!m_pluginXmlDoc.LoadFile(scriptFileName))
- {
- CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", scriptFileName.c_str(), m_pluginXmlDoc.ErrorRow(), m_pluginXmlDoc.ErrorDesc());
- return false;
- }
-
- // Make sure that the script XML has the settings element
- TiXmlElement *setting = m_pluginXmlDoc.RootElement();
- if (!setting || strcasecmp(setting->Value(), "settings") != 0)
- {
- CLog::Log(LOGERROR, "Error loading Settings %s: cannot find root element 'settings'", scriptFileName.c_str());
- return false;
- }
-
- // Load the user saved settings. If it does not exist, create it
- if (!m_userXmlDoc.LoadFile(m_userFileName))
- {
- TiXmlDocument doc;
- TiXmlDeclaration decl("1.0", "UTF-8", "yes");
- doc.InsertEndChild(decl);
-
- TiXmlElement xmlRootElement("settings");
- doc.InsertEndChild(xmlRootElement);
-
- m_userXmlDoc = doc;
-
- // Don't worry about the actual settings, they will be set when the user clicks "Ok"
- // in the settings dialog
- }
-
- return true;
-}
-
-bool CScriptSettings::Save(void)
-{
- // break down the path into directories
- CStdString strRoot, strType, strScript;
- CUtil::GetDirectory(m_userFileName, strScript);
- CUtil::RemoveSlashAtEnd(strScript);
- CUtil::GetDirectory(strScript, strType);
- CUtil::RemoveSlashAtEnd(strType);
- CUtil::GetDirectory(strType, strRoot);
- CUtil::RemoveSlashAtEnd(strRoot);
-
- // create the individual folders
- if (!XFILE::CDirectory::Exists(strRoot))
- XFILE::CDirectory::Create(strRoot);
- if (!XFILE::CDirectory::Exists(strType))
- XFILE::CDirectory::Create(strType);
- if (!XFILE::CDirectory::Exists(strScript))
- XFILE::CDirectory::Create(strScript);
-
- return m_userXmlDoc.SaveFile(m_userFileName);
-}
-
-bool CScriptSettings::SettingsExist(const CStdString& strPath)
-{
- CStdString scriptFileName = strPath;
- CUtil::RemoveSlashAtEnd(scriptFileName);
-
- CUtil::AddFileToFolder(scriptFileName, "resources", scriptFileName);
- CUtil::AddFileToFolder(scriptFileName, "settings.xml", scriptFileName);
-
- // Load the settings file to verify it's valid
- TiXmlDocument xmlDoc;
- if (!xmlDoc.LoadFile(scriptFileName))
- return false;
-
- // Make sure that the script XML has the settings element
- TiXmlElement *setting = xmlDoc.RootElement();
- if (!setting || strcasecmp(setting->Value(), "settings") != 0)
- return false;
-
- return true;
-}
-
-CScriptSettings& CScriptSettings::operator=(const CBasicSettings& settings)
-{
- *((CBasicSettings*)this) = settings;
-
- return *this;
-}
-
diff --git a/xbmc/Settings.cpp b/xbmc/Settings.cpp index ec96d8d91b..6ed75b4649 100644 --- a/xbmc/Settings.cpp +++ b/xbmc/Settings.cpp @@ -33,6 +33,8 @@ #include "ButtonTranslator.h" #include "XMLUtils.h" #include "utils/PasswordManager.h" +#include "utils/RegExp.h" +#include "GUIPassword.h" #include "GUIAudioManager.h" #include "AudioContext.h" #include "utils/GUIInfoManager.h" @@ -1063,6 +1065,10 @@ bool CSettings::LoadProfiles(const CStdString& strSettingsFile) profile.setWriteSources(bHas); bHas = false; + XMLUtils::GetBoolean(pProfile, "lockaddonmanager", bHas); + profile.setAddonManagerLocked(bHas); + + bHas = false; XMLUtils::GetBoolean(pProfile, "locksettings", bHas); profile.setSettingsLocked(bHas); @@ -1139,6 +1145,7 @@ bool CSettings::SaveProfiles(const CStdString& strSettingsFile) const XMLUtils::SetBoolean(pNode,"lockpictures",m_vecProfiles[iProfile].picturesLocked()); XMLUtils::SetBoolean(pNode,"lockprograms",m_vecProfiles[iProfile].programsLocked()); XMLUtils::SetBoolean(pNode,"locksettings",m_vecProfiles[iProfile].settingsLocked()); + XMLUtils::SetBoolean(pNode,"lockaddonmanager",m_vecProfiles[iProfile].addonmanagerLocked()); XMLUtils::SetBoolean(pNode,"lockfiles",m_vecProfiles[iProfile].filesLocked()); } @@ -1952,6 +1959,7 @@ void CSettings::CreateProfileFolders() CDirectory::Create(CUtil::AddFileToFolder(GetMusicThumbFolder(), strHex)); CDirectory::Create(CUtil::AddFileToFolder(GetVideoThumbFolder(), strHex)); } + CDirectory::Create("special://profile/addon_data"); CDirectory::Create("special://profile/keymaps"); - CDirectory::Create("special://profile/visualisations"); } + diff --git a/xbmc/StringUtils.cpp b/xbmc/StringUtils.cpp index 34b32993f3..e82c80dfde 100644 --- a/xbmc/StringUtils.cpp +++ b/xbmc/StringUtils.cpp @@ -31,14 +31,18 @@ #include "StringUtils.h" +#include "utils/RegExp.h" #include <math.h> #include <sstream> using namespace std; +const char* ADDON_GUID_RE = "^(\\{){0,1}[0-9a-fA-F]{8}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{4}\\-[0-9a-fA-F]{12}(\\}){0,1}$"; + /* empty string for use in returns by ref */ const CStdString StringUtils::EmptyString = ""; +CStdString StringUtils::m_lastUUID = ""; void StringUtils::JoinString(const CStdStringArray &strings, const CStdString& delimiter, CStdString& result) { @@ -383,3 +387,58 @@ void StringUtils::WordToDigits(CStdString &word) } } +CStdString StringUtils::CreateUUID() +{ + /* This function generate a DCE 1.1, ISO/IEC 11578:1996 and IETF RFC-4122 + * Version 4 conform local unique UUID based upon random number generation. + */ + char UuidStrTmp[40]; + char *pUuidStr = UuidStrTmp; + int i; + + /* generate hash from last generated UUID string */ + unsigned seed = 0; + for (unsigned i = 0; i < m_lastUUID.length(); i++) { + seed = 31*seed + m_lastUUID[i]; + } + + /* use hash as the seed for rand()*/ + srand(seed); + + /*Data1 - 8 characters.*/ + for(i = 0; i < 8; i++, pUuidStr++) + ((*pUuidStr = (rand() % 16)) < 10) ? *pUuidStr += 48 : *pUuidStr += 55; + + /*Data2 - 4 characters.*/ + *pUuidStr++ = '-'; + for(i = 0; i < 4; i++, pUuidStr++) + ((*pUuidStr = (rand() % 16)) < 10) ? *pUuidStr += 48 : *pUuidStr += 55; + + /*Data3 - 4 characters.*/ + *pUuidStr++ = '-'; + for(i = 0; i < 4; i++, pUuidStr++) + ((*pUuidStr = (rand() % 16)) < 10) ? *pUuidStr += 48 : *pUuidStr += 55; + + /*Data4 - 4 characters.*/ + *pUuidStr++ = '-'; + for(i = 0; i < 4; i++, pUuidStr++) + ((*pUuidStr = (rand() % 16)) < 10) ? *pUuidStr += 48 : *pUuidStr += 55; + + /*Data5 - 12 characters.*/ + *pUuidStr++ = '-'; + for(i = 0; i < 12; i++, pUuidStr++) + ((*pUuidStr = (rand() % 16)) < 10) ? *pUuidStr += 48 : *pUuidStr += 55; + + *pUuidStr = '\0'; + + m_lastUUID = UuidStrTmp; + return UuidStrTmp; +} + +bool StringUtils::ValidateUUID(const CStdString &uuid) +{ + CRegExp guidRE; + guidRE.RegComp(ADDON_GUID_RE); + return (guidRE.RegFind(uuid.c_str()) == 0); +} + diff --git a/xbmc/StringUtils.h b/xbmc/StringUtils.h index a59cf337f1..7afebe2626 100644 --- a/xbmc/StringUtils.h +++ b/xbmc/StringUtils.h @@ -54,6 +54,10 @@ public: static int FindEndBracket(const CStdString &str, char opener, char closer, int startPos = 0); static int DateStringToYYYYMMDD(const CStdString &dateString); static void WordToDigits(CStdString &word); + static CStdString CreateUUID(); + static bool ValidateUUID(const CStdString &uuid); // NB only validates syntax +private: + static CStdString m_lastUUID; }; #endif diff --git a/xbmc/URL.cpp b/xbmc/URL.cpp index 24722328e8..ba07315239 100644 --- a/xbmc/URL.cpp +++ b/xbmc/URL.cpp @@ -26,12 +26,14 @@ #include "FileSystem/File.h" #include "FileItem.h" #include "FileSystem/StackDirectory.h" +#include "utils/Addon.h" #ifndef _LINUX #include <sys\types.h> #include <sys\stat.h> #endif using namespace std; +using namespace ADDON; CStdString URLEncodeInline(const CStdString& strData) { @@ -188,7 +190,7 @@ void CURL::Parse(const CStdString& strURL1) else if(strProtocol2.Equals("http") || strProtocol2.Equals("https") - || strProtocol2.Equals("plugin") + || TranslateContent(m_strProtocol) != CONTENT_NONE // plugin paths || strProtocol2.Equals("hdhomerun") || strProtocol2.Equals("rtsp") || strProtocol2.Equals("zip")) diff --git a/xbmc/Util.cpp b/xbmc/Util.cpp index e643f4742e..af0a6b16fb 100644 --- a/xbmc/Util.cpp +++ b/xbmc/Util.cpp @@ -745,7 +745,7 @@ bool CUtil::HasSlashAtEnd(const CStdString& strFile) bool CUtil::IsRemote(const CStdString& strFile) { - if (IsCDDA(strFile) || IsISO9660(strFile) || IsPlugin(strFile)) + if (IsCDDA(strFile) || IsISO9660(strFile)) return false; if (IsSpecial(strFile)) @@ -986,7 +986,7 @@ bool CUtil::IsSpecial(const CStdString& strFile) bool CUtil::IsPlugin(const CStdString& strFile) { CURL url(strFile); - return url.GetProtocol().Equals("plugin") && !url.GetFileName().IsEmpty(); + return !url.GetProtocol().IsEmpty() && StringUtils::ValidateUUID(url.GetHostName()); } bool CUtil::IsPluginRoot(const CStdString& strFile) diff --git a/xbmc/VideoDatabase.cpp b/xbmc/VideoDatabase.cpp index 43c429a2a3..abbeb9667e 100644 --- a/xbmc/VideoDatabase.cpp +++ b/xbmc/VideoDatabase.cpp @@ -22,6 +22,7 @@ #include "VideoDatabase.h" #include "GUIWindowVideoBase.h" #include "utils/RegExp.h" +#include "utils/AddonManager.h" #include "utils/GUIInfoManager.h" #include "Util.h" #include "XMLUtils.h" @@ -48,6 +49,7 @@ using namespace std; using namespace dbiplus; using namespace XFILE; using namespace VIDEO; +using namespace ADDON; #define VIDEO_DATABASE_VIEW_TVSHOW "SELECT tvshow.*,path.strPath AS strPath," \ "counts.totalcount AS totalCount,counts.watchedcount AS watchedCount," \ @@ -3199,7 +3201,7 @@ void CVideoDatabase::RemoveContentForPath(const CStdString& strPath, CGUIDialogP progress->Close(); } -void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const SScraperInfo& info, const VIDEO::SScanSettings& settings) +void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const ScraperPtr& scraper, const VIDEO::SScanSettings& settings) { // if we have a multipath, set scraper for all contained paths too if(CUtil::IsMultiPath(filePath)) @@ -3208,7 +3210,7 @@ void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const SScrape CMultiPathDirectory::GetPaths(filePath, paths); for(unsigned i=0;i<paths.size();i++) - SetScraperForPath(paths[i],info,settings); + SetScraperForPath(paths[i],scraper,settings); } try @@ -3223,7 +3225,20 @@ void CVideoDatabase::SetScraperForPath(const CStdString& filePath, const SScrape } // Update - CStdString strSQL=FormatSQL("update path set strContent='%s',strScraper='%s', scanRecursive=%i, useFolderNames=%i, strSettings='%s', noUpdate=%i where idPath=%i", info.strContent.c_str(), info.strPath.c_str(),settings.recurse,settings.parent_name,info.settings.GetSettings().c_str(),settings.noupdate, idPath); + CStdString strSQL; + if (settings.exclude) + { //NB See note in ::GetScraperForPath about strContent=='none' + strSQL=FormatSQL("update path set strContent='none', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0 where idPath=%i", idPath); + } + else if(!scraper) + { // catch clearing content, but not excluding + strSQL=FormatSQL("update path set strContent='', strScraper='', scanRecursive=0, useFolderNames=0, strSettings='', noUpdate=0 where idPath=%i", idPath); + } + else + { + CStdString content = TranslateContent(scraper->Content()); + strSQL=FormatSQL("update path set strContent='%s', strScraper='%s', scanRecursive=%i, useFolderNames=%i, strSettings='%s', noUpdate=%i where idPath=%i", content.c_str(), scraper->UUID().c_str(),settings.recurse,settings.parent_name,scraper->GetSettings().c_str(),settings.noupdate, idPath); + } m_pDS->exec(strSQL.c_str()); } catch (...) @@ -5498,29 +5513,28 @@ int CVideoDatabase::GetMusicVideoCount(const CStdString& strWhere) return 0; } -bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& info) +bool CVideoDatabase::GetScraperForPath( const CStdString& strPath, ScraperPtr& scraper ) { int iDummy; - return GetScraperForPath(strPath, info, iDummy); + return GetScraperForPath(strPath, scraper, iDummy); } -bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& info, int& iFound) +bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, ScraperPtr& scraper, int& iFound) { SScanSettings settings; - return GetScraperForPath(strPath, info, settings, iFound); + return GetScraperForPath(strPath, scraper, settings, iFound); } -bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& info, SScanSettings& settings) +bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, ScraperPtr& scraper, SScanSettings& settings) { int iDummy; - return GetScraperForPath(strPath, info, settings, iDummy); + return GetScraperForPath(strPath, scraper, settings, iDummy); } -bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& info, SScanSettings& settings, int& iFound) +bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, ScraperPtr& scraper, SScanSettings& settings, int& iFound) { try { - info.Reset(); if (strPath.IsEmpty()) return false; if (NULL == m_pDB.get()) return false; if (NULL == m_pDS.get()) return false; @@ -5542,59 +5556,100 @@ bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& iFound = 1; if (!m_pDS->eof()) - { - info.strContent = m_pDS->fv("path.strContent").get_asString(); - info.strPath = m_pDS->fv("path.strScraper").get_asString(); - info.settings.LoadUserXML(m_pDS->fv("path.strSettings").get_asString()); - - CScraperParser parser; - parser.Load("special://xbmc/system/scrapers/video/" + info.strPath); - info.strLanguage = parser.GetLanguage(); - info.strTitle = parser.GetName(); - info.strDate = parser.GetDate(); - info.strFramework = parser.GetFramework(); - - settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool(); - settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt(); - settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool(); - } - if (info.strContent.IsEmpty()) - { - CStdString strParent; - - while (CUtil::GetParentPath(strPath1, strParent)) + { //!!! + //FIXME confusion arises here as VIDEODB_CONTENT_NONE has no relation to strContent == 'none'. + // Here, we are referring to paths which are explicitly excluded from scraping, by + // having settings.exclude == true + //!! + CStdString strcontent = m_pDS->fv("path.strContent").get_asString(); + strcontent.ToLower(); + if (strcontent.Equals("none")) { - iFound++; + settings.exclude = true; + scraper.reset(); + m_pDS->close(); + return false; + } - CStdString strSQL=FormatSQL("select path.strContent,path.strScraper,path.scanRecursive,path.useFolderNames,path.strSettings,path.noUpdate from path where strPath like '%s'",strParent.c_str()); - m_pDS->query(strSQL.c_str()); - if (!m_pDS->eof()) - { - info.strContent = m_pDS->fv("path.strContent").get_asString(); - info.strPath = m_pDS->fv("path.strScraper").get_asString(); - info.settings.LoadUserXML(m_pDS->fv("path.strSettings").get_asString()); + // path is not excluded, find out if content is set + // then try and ascertain scraper for this path + CONTENT_TYPE content = TranslateContent(strcontent); + CStdString scraperUUID = m_pDS->fv("path.strScraper").get_asString(); - CScraperParser parser; - parser.Load("special://xbmc/system/scrapers/video/" + info.strPath); - info.strLanguage = parser.GetLanguage(); - info.strTitle = parser.GetName(); - info.strDate = parser.GetDate(); - info.strFramework = parser.GetFramework(); + if (content != CONTENT_NONE) + { // content set, use pre configured or default scraper + AddonPtr addon; + if (!scraperUUID.empty() && + CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRAPER, scraperUUID, addon)) + { + scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon)); + if (!scraper) + return false; + // store this path's content & settings + scraper->m_pathContent = content; + scraper->LoadUserXML(m_pDS->fv("path.strSettings").get_asString()); settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool(); settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt(); settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool(); - - if (!info.strContent.IsEmpty()) - break; } + else + { // use default scraper for this content type + if (CAddonMgr::Get()->GetDefault(ADDON::ADDON_SCRAPER, addon, content)) + { + scraper = boost::dynamic_pointer_cast<CScraper>(addon->Clone(addon)); + if (scraper) + { + scraper->m_pathContent = content; + settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool(); + settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt(); + settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool(); + } + } + } + } + else + { // no content set for this path (ie path.strContent == '') + // we must drill up until a scraper is configured + CStdString strParent; + while (CUtil::GetParentPath(strPath1, strParent)) + { + iFound++; - strPath1 = strParent; + CStdString strSQL=FormatSQL("select path.strContent,path.strScraper,path.scanRecursive,path.useFolderNames,path.strSettings,path.noUpdate from path where strPath like '%s'",strParent.c_str()); + m_pDS->query(strSQL.c_str()); + if (!m_pDS->eof()) + { + AddonPtr defaultScraper; + if (!CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRAPER, m_pDS->fv("path.strScraper").get_asString(), defaultScraper)) + { + strPath1 = strParent; + continue; + } + + scraper = boost::dynamic_pointer_cast<CScraper>(defaultScraper->Clone(defaultScraper)); + content = TranslateContent(m_pDS->fv("path.strContent").get_asString()); + scraper->m_pathContent = content; + scraper->LoadUserXML(m_pDS->fv("path.strSettings").get_asString()); + settings.parent_name = m_pDS->fv("path.useFolderNames").get_asBool(); + settings.recurse = m_pDS->fv("path.scanRecursive").get_asInt(); + settings.noupdate = m_pDS->fv("path.noUpdate").get_asBool(); + settings.exclude = false; + + //TODO fix CONTENT_NONE storage in db, per discussion + if (!content == CONTENT_NONE) + break; + } + strPath1 = strParent; + } } } m_pDS->close(); - if (info.strContent.Equals("tvshows")) + if (!scraper) + return false; + + if (scraper->Content() == CONTENT_TVSHOWS) { settings.recurse = 0; if(settings.parent_name) // single show @@ -5608,13 +5663,13 @@ bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& return iFound <= 3; } } - else if (info.strContent.Equals("movies")) + else if (scraper->Content() == CONTENT_MOVIES) { settings.recurse = settings.recurse - (iFound-1); settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1); return settings.recurse >= 0; } - else if (info.strContent.Equals("musicvideos")) + else if (scraper->Content() == CONTENT_MUSICVIDEOS) { settings.recurse = settings.recurse - (iFound-1); settings.parent_name_root = settings.parent_name && (!settings.recurse || iFound > 1); @@ -5623,11 +5678,6 @@ bool CVideoDatabase::GetScraperForPath(const CStdString& strPath, SScraperInfo& else { iFound = 0; - // this is setup so set content dialog will show correct defaults - settings.recurse = -1; - settings.parent_name = false; - settings.parent_name_root = false; - settings.noupdate = false; return false; } } @@ -7384,7 +7434,7 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f TiXmlNode *pPaths = pMain->InsertEndChild(xmlPathElement); for( map<CStdString,SScanSettings>::iterator iter=paths.begin();iter != paths.end();++iter) { - SScraperInfo info; + ScraperPtr info; int iFound=0; if (GetScraperForPath(iter->first,info,iFound) && iFound == 1) { @@ -7393,8 +7443,8 @@ void CVideoDatabase::ExportToXML(const CStdString &path, bool singleFiles /* = f XMLUtils::SetString(pPath,"url",iter->first); XMLUtils::SetInt(pPath,"scanrecursive",iter->second.recurse); XMLUtils::SetBoolean(pPath,"usefoldernames",iter->second.parent_name); - XMLUtils::SetString(pPath,"content",info.strContent); - XMLUtils::SetString(pPath,"scraperpath",info.strPath); + XMLUtils::SetString(pPath,"content", TranslateContent(info->Content())); + XMLUtils::SetString(pPath,"scraperpath",info->UUID()); } } xmlDoc.SaveFile(xmlFile); @@ -7523,7 +7573,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path) { info.Load(movie); CFileItem item(info); - scanner.AddMovie(&item,"movies",info); + scanner.AddMovie(&item,CONTENT_MOVIES,info); SetPlayCount(item, info.m_playCount, info.m_lastPlayed); CStdString file(GetSafeFile(moviesDir, info.m_strTitle)); CFile::Cache(file + ".tbn", item.GetCachedVideoThumb()); @@ -7536,7 +7586,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path) { info.Load(movie); CFileItem item(info); - scanner.AddMovie(&item,"musicvideos",info); + scanner.AddMovie(&item,CONTENT_MUSICVIDEOS,info); SetPlayCount(item, info.m_playCount, info.m_lastPlayed); CStdString file(GetSafeFile(musicvideosDir, info.m_strArtist + "." + info.m_strTitle)); CFile::Cache(file + ".tbn", item.GetCachedVideoThumb()); @@ -7550,7 +7600,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path) CUtil::AddSlashAtEnd(info.m_strPath); DeleteTvShow(info.m_strPath); CFileItem item(info); - int showID = scanner.AddMovie(&item,"tvshows",info); + int showID = scanner.AddMovie(&item,CONTENT_TVSHOWS,info); current++; CStdString showDir(GetSafeFile(tvshowsDir, info.m_strTitle)); CFile::Cache(CUtil::AddFileToFolder(showDir, "folder.jpg"), item.GetCachedVideoThumb()); @@ -7565,7 +7615,7 @@ void CVideoDatabase::ImportFromXML(const CStdString &path) CVideoInfoTag info; info.Load(episode); CFileItem item(info); - scanner.AddMovie(&item,"tvshows",info,showID); + scanner.AddMovie(&item,CONTENT_TVSHOWS,info,showID); SetPlayCount(item, info.m_playCount, info.m_lastPlayed); CStdString file; file.Format("s%02ie%02i.tbn", info.m_iSeason, info.m_iEpisode); @@ -7584,13 +7634,29 @@ void CVideoDatabase::ImportFromXML(const CStdString &path) { CStdString strPath; XMLUtils::GetString(path,"url",strPath); - SScraperInfo info; - SScanSettings settings; - XMLUtils::GetString(path,"content",info.strContent); - XMLUtils::GetString(path,"scraperpath",info.strPath); - XMLUtils::GetInt(path,"scanrecursive",settings.recurse); - XMLUtils::GetBoolean(path,"usefoldernames",settings.parent_name); - SetScraperForPath(strPath,info,settings); + CStdString content; + + if (XMLUtils::GetString(path,"content", content)) + { // check the scraper exists, if so store the path + AddonPtr addon; + CStdString uuid; + + if (!XMLUtils::GetString(path,"scraperuuid",uuid)) + { // support pre addons exports + XMLUtils::GetString(path, "scraperpath", uuid); + uuid = CUtil::GetFileName(uuid); + } + + if (CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRAPER, uuid, addon)) + { + SScanSettings settings; + ScraperPtr scraper = boost::dynamic_pointer_cast<CScraper>(addon); + scraper->m_pathContent = TranslateContent(content); + XMLUtils::GetInt(path,"scanrecursive",settings.recurse); + XMLUtils::GetBoolean(path,"usefoldernames",settings.parent_name); + SetScraperForPath(strPath,scraper,settings); + } + } path = path->NextSiblingElement(); } } @@ -7711,14 +7777,16 @@ void CVideoDatabase::SplitPath(const CStdString& strFileNameAndPath, CStdString& void CVideoDatabase::InvalidatePathHash(const CStdString& strPath) { - SScraperInfo info; + ScraperPtr info; SScanSettings settings; int iFound; GetScraperForPath(strPath,info,settings,iFound); SetPathHash(strPath,""); - if (info.strContent.Equals("tvshows") || (info.strContent.Equals("movies") && iFound != 1)) // if we scan by folder name we need to invalidate parent as well + if (!info) + return; + if (info->Content() == CONTENT_TVSHOWS || (info->Content() == CONTENT_MOVIES && iFound != 1)) // if we scan by folder name we need to invalidate parent as well { - if (info.strContent.Equals("tvshows") || settings.parent_name_root) + if (info->Content() == CONTENT_TVSHOWS || settings.parent_name_root) { CStdString strParent; CUtil::GetParentPath(strPath,strParent); diff --git a/xbmc/VideoDatabase.h b/xbmc/VideoDatabase.h index 724518e949..614508f3f0 100644 --- a/xbmc/VideoDatabase.h +++ b/xbmc/VideoDatabase.h @@ -21,12 +21,12 @@ */ #include "Database.h" #include "VideoInfoTag.h" +#include "Scraper.h" #include "Bookmark.h" #include <memory> #include <set> -struct SScraperInfo; class CFileItem; class CFileItemList; class CVideoSettings; @@ -389,11 +389,12 @@ public: void DeleteBookMarkForEpisode(const CVideoInfoTag& tag); // scraper settings - void SetScraperForPath(const CStdString& filePath, const SScraperInfo& info, const VIDEO::SScanSettings& settings); - bool GetScraperForPath(const CStdString& strPath, SScraperInfo& info); - bool GetScraperForPath(const CStdString& strPath, SScraperInfo& info, int& iFound); - bool GetScraperForPath(const CStdString& strPath, SScraperInfo& info, VIDEO::SScanSettings& settings); - bool GetScraperForPath(const CStdString& strPath, SScraperInfo& info, VIDEO::SScanSettings& settings, int& iFound); + void SetScraperForPath(const CStdString& filePath, const ADDON::ScraperPtr& info, const VIDEO::SScanSettings& settings); + bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& scraper); + bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& scraper, int& iFound); + bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings); + bool GetScraperForPath(const CStdString& strPath, ADDON::ScraperPtr& scraper, VIDEO::SScanSettings& settings, int& iFound); + CONTENT_TYPE GetContentForPath(const CStdString& strPath); // scanning hashes and paths scanned bool SetPathHash(const CStdString &path, const CStdString &hash); diff --git a/xbmc/VideoInfoScanner.cpp b/xbmc/VideoInfoScanner.cpp index 06c62ed2bb..8353288db3 100644 --- a/xbmc/VideoInfoScanner.cpp +++ b/xbmc/VideoInfoScanner.cpp @@ -21,6 +21,7 @@ #include "FileItem.h" #include "VideoInfoScanner.h" +#include "AddonManager.h" #include "FileSystem/DirectoryCache.h" #include "Util.h" #include "NfoFile.h" @@ -44,6 +45,7 @@ using namespace std; using namespace XFILE; +using namespace ADDON; namespace VIDEO { @@ -135,7 +137,7 @@ namespace VIDEO } } - void CVideoInfoScanner::Start(const CStdString& strDirectory, const SScraperInfo& info, const SScanSettings& settings, bool bUpdateAll) + void CVideoInfoScanner::Start(const CStdString& strDirectory, const ScraperPtr& info, const SScanSettings& settings, bool bUpdateAll) { m_strStartDir = strDirectory; m_bUpdateAll = bUpdateAll; @@ -200,12 +202,19 @@ namespace VIDEO CFileItemList items; int iFound; bool bSkip=false; - m_database.GetScraperForPath(strDirectory,m_info,settings, iFound); - if (m_info.strContent.IsEmpty() || m_info.strContent.Equals("None")) + // first time m_info is set + + if (!m_database.GetScraperForPath(strDirectory,m_info,settings, iFound)) + { + m_info.reset(); + return false; + } + + if (m_info->Content() == CONTENT_NONE) bSkip = true; CStdString hash, dbHash; - if (m_info.strContent.Equals("movies") && !settings.noupdate) + if (m_info->Content() == CONTENT_MOVIES && !settings.noupdate) { if (m_pObserver) m_pObserver->OnStateChanged(FETCHING_MOVIE_INFO); @@ -237,7 +246,7 @@ namespace VIDEO bSkip = true; } } - else if (m_info.strContent.Equals("tvshows") && !settings.noupdate) + else if (m_info->Content() == CONTENT_TVSHOWS && !settings.noupdate) { if (m_pObserver) m_pObserver->OnStateChanged(FETCHING_TVSHOW_INFO); @@ -265,7 +274,7 @@ namespace VIDEO CUtil::GetParentPath(item->m_strPath,items.m_strPath); } } - else if (m_info.strContent.Equals("musicvideos") && !settings.noupdate) + else if (m_info->Content() == CONTENT_MUSICVIDEOS && !settings.noupdate) { if (m_pObserver) m_pObserver->OnStateChanged(FETCHING_MUSICVIDEO_INFO); @@ -297,27 +306,13 @@ namespace VIDEO } } - CLog::Log(LOGDEBUG,"Hash[%s,%s]:DB=[%s],Computed=[%s]", - m_info.strContent.c_str(),strDirectory.c_str(),dbHash.c_str(),hash.c_str()); - - if (!m_info.settings.GetPluginRoot() && m_info.settings.GetSettings().IsEmpty()) // check for settings, if they are around load defaults - to workaround the nastyness - { - CScraperParser parser; - CStdString strPath; - if (!m_info.strContent.IsEmpty()) - strPath = "special://xbmc/system/scrapers/video/" + m_info.strPath; - if (!strPath.IsEmpty() && parser.Load(strPath) && parser.HasFunction("GetSettings")) - { - if (m_info.settings.LoadSettingsXML("special://xbmc/system/scrapers/video/" + m_info.strPath)) - m_info.settings.SaveFromDefault(); - } - } + CLog::Log(LOGDEBUG,"Hash[%s,%s]:DB=[%s],Computed=[%s]", TranslateContent(m_info->Content()).c_str(),strDirectory.c_str(),dbHash.c_str(),hash.c_str()); if (!bSkip) { if (RetrieveVideoInfo(items,settings.parent_name_root,m_info)) { - if (!m_bStop && (m_info.strContent.Equals("movies") || m_info.strContent.Equals("musicvideos"))) + if (!m_bStop && (m_info->Content() == CONTENT_MOVIES || m_info->Content() == CONTENT_MUSICVIDEOS)) { m_database.SetPathHash(strDirectory, hash); m_pathsToClean.push_back(m_database.GetPathId(strDirectory)); @@ -335,7 +330,7 @@ namespace VIDEO CLog::Log(LOGDEBUG, "%s - Finished dir: %s", __FUNCTION__, strDirectory.c_str()); // exclude folders that match our exclude regexps - CStdStringArray regexps = m_info.strContent.Equals("tvshows") ? g_advancedSettings.m_tvshowExcludeFromScanRegExps + CStdStringArray regexps = m_info->Content() == CONTENT_TVSHOWS ? g_advancedSettings.m_tvshowExcludeFromScanRegExps : g_advancedSettings.m_moviesExcludeFromScanRegExps; for (int i = 0; i < items.Size(); ++i) @@ -346,7 +341,7 @@ namespace VIDEO break; // if we have a directory item (non-playlist) we then recurse into that folder - if (pItem->m_bIsFolder && !pItem->GetLabel().Equals("sample") && !pItem->GetLabel().Equals("subs") && !pItem->IsParentFolder() && !pItem->IsPlayList() && settings.recurse > 0 && !m_info.strContent.Equals("tvshows")) // do not recurse for tv shows - we have already looked recursively for episodes + if (pItem->m_bIsFolder && !pItem->GetLabel().Equals("sample") && !pItem->GetLabel().Equals("subs") && !pItem->IsParentFolder() && !pItem->IsPlayList() && settings.recurse > 0 && m_info->Content() != CONTENT_TVSHOWS) // do not recurse for tv shows - we have already looked recursively for episodes { CStdString strPath=pItem->m_strPath; @@ -371,9 +366,9 @@ namespace VIDEO return !m_bStop; } - bool CVideoInfoScanner::RetrieveVideoInfo(CFileItemList& items, bool bDirNames, const SScraperInfo& info, bool bRefresh, CScraperUrl* pURL, CGUIDialogProgress* pDlgProgress, bool ignoreNfo) + bool CVideoInfoScanner::RetrieveVideoInfo(CFileItemList& items, bool bDirNames, const ScraperPtr& scraper, bool bRefresh, CScraperUrl* pURL, CGUIDialogProgress* pDlgProgress, bool ignoreNfo) { - m_IMDB.SetScraperInfo(info); + m_IMDB.SetScraperInfo(scraper); if (pDlgProgress) { @@ -406,41 +401,23 @@ namespace VIDEO CFileItemPtr pItem = items[i]; // we do this since we may have a override per dir - SScraperInfo info2; + ScraperPtr info2; if (pItem->m_bIsFolder) m_database.GetScraperForPath(pItem->m_strPath,info2); else m_database.GetScraperForPath(items.m_strPath,info2); - if (info2.strContent.Equals("None")) // skip + if (!info2 || info2->Content() == CONTENT_NONE) // skip continue; - if (!info2.settings.GetPluginRoot() && info2.settings.GetSettings().IsEmpty()) // check for settings, if they are around load defaults - to workaround the nastyness - { - CScraperParser parser; - if (parser.Load("special://xbmc/system/scrapers/video/"+info2.strPath) && parser.HasFunction("GetSettings")) - { - if (info2.settings.LoadSettingsXML("special://xbmc/system/scrapers/video/" + info2.strPath)) - info2.settings.SaveFromDefault(); - else if (!DownloadFailed(pDlgProgress)) - return false; - else - continue; - } - } - - // we might override scraper - if (info2.strContent == info.strContent) - info2.strPath = info.strPath; - m_IMDB.SetScraperInfo(info2); // Discard all exclude files defined by regExExclude - if (CUtil::ExcludeFileOrFolder(pItem->m_strPath, info.strContent.Equals("tvshows") ? g_advancedSettings.m_tvshowExcludeFromScanRegExps + if (CUtil::ExcludeFileOrFolder(pItem->m_strPath, scraper->Content() == CONTENT_TVSHOWS ? g_advancedSettings.m_tvshowExcludeFromScanRegExps : g_advancedSettings.m_moviesExcludeFromScanRegExps)) continue; - if (info2.strContent.Equals("movies") || info2.strContent.Equals("musicvideos")) + if (info2->Content() == CONTENT_MOVIES || info2->Content() == CONTENT_MUSICVIDEOS) { if (m_pObserver) { @@ -450,7 +427,7 @@ namespace VIDEO } } - if (info2.strContent.Equals("tvshows")) + if (info2->Content() == CONTENT_TVSHOWS) { if (pItem->m_bIsFolder) idTvShow = m_database.GetTvShowId(pItem->m_strPath); @@ -514,21 +491,21 @@ namespace VIDEO } } - if (!pItem->m_bIsFolder || info2.strContent.Equals("tvshows")) + if (!pItem->m_bIsFolder || info2->Content() == CONTENT_TVSHOWS) { - if ((pItem->IsVideo() && !pItem->IsNFO() && !pItem->IsPlayList()) || info2.strContent.Equals("tvshows") ) + if ((pItem->IsVideo() && !pItem->IsNFO() && !pItem->IsPlayList()) || info2->Content() == CONTENT_TVSHOWS ) { if (pDlgProgress) { int iString=198; - if (info2.strContent.Equals("tvshows")) + if (info2->Content() == CONTENT_TVSHOWS) { if (pItem->m_bIsFolder) iString = 20353; else iString = 20361; } - if (info2.strContent.Equals("musicvideos")) + if (info2->Content() == CONTENT_MUSICVIDEOS) iString = 20394; pDlgProgress->SetHeading(iString); pDlgProgress->SetLine(0, pItem->GetLabel()); @@ -548,8 +525,8 @@ namespace VIDEO m_database.Close(); return false; } - if ((info2.strContent.Equals("movies") && m_database.HasMovieInfo(pItem->m_strPath)) || - (info2.strContent.Equals("musicvideos") && m_database.HasMusicVideoInfo(pItem->m_strPath))) + if ((info2->Content() == CONTENT_MOVIES && m_database.HasMovieInfo(pItem->m_strPath)) || + (info2->Content() == CONTENT_MUSICVIDEOS && m_database.HasMusicVideoInfo(pItem->m_strPath))) continue; CNfoFile::NFOResult result=CNfoFile::NO_NFO; @@ -559,13 +536,19 @@ namespace VIDEO result = CheckForNFOFile(pItem.get(),bDirNames,info2,scrUrl); if (result == CNfoFile::ERROR_NFO) continue; - if (info2.strContent.Equals("tvshows") && result != CNfoFile::NO_NFO) - { - SScraperInfo info3(info2); + if (info2->Content() == CONTENT_TVSHOWS && result != CNfoFile::NO_NFO) + { //FIXME this comment doesn't match second comment + // check for preconfigured scraper; if found, overwrite with interpreted scraper but keep current scan settings + ScraperPtr temp; SScanSettings settings; - m_database.GetScraperForPath(pItem->m_strPath,info3,settings); - info3.strPath = info2.strPath; - m_database.SetScraperForPath(pItem->m_strPath,info3,settings); + if (m_database.GetScraperForPath(pItem->m_strPath,temp,settings)) + { + if (temp->Parent()) + { // as we are working with a new clone, default scraper settings are saved + temp = boost::dynamic_pointer_cast<CScraper>(temp->Parent()); + m_database.SetScraperForPath(pItem->m_strPath,temp,settings); + } + } } if (result == CNfoFile::FULL_NFO) { @@ -574,10 +557,10 @@ namespace VIDEO if (m_pObserver) m_pObserver->OnSetTitle(pItem->GetVideoInfoTag()->m_strTitle); - long lResult = AddMovieAndGetThumb(pItem.get(), info2.strContent, *pItem->GetVideoInfoTag(), -1, bDirNames, bRefresh, pDlgProgress); - if (bRefresh && info.strContent.Equals("tvshows") && g_guiSettings.GetBool("videolibrary.seasonthumbs")) + long lResult = AddMovieAndGetThumb(pItem.get(), info2->Content(), *pItem->GetVideoInfoTag(), -1, bDirNames, bRefresh, pDlgProgress); + if (bRefresh && scraper->Content() == CONTENT_TVSHOWS && g_guiSettings.GetBool("videolibrary.seasonthumbs")) FetchSeasonThumbs(lResult); - if (!bRefresh && info2.strContent.Equals("tvshows")) + if (!bRefresh && info2->Content() == CONTENT_TVSHOWS) i--; Return = true; continue; @@ -609,18 +592,17 @@ namespace VIDEO if (m_pObserver && !url.strTitle.IsEmpty()) m_pObserver->OnSetTitle(url.strTitle); long lResult=1; - - // force thumb and fanart - bool bForce(false); + // force thumb and fanart + bool bForce(false); if (result==CNfoFile::NO_NFO || result==CNfoFile::ERROR_NFO) bForce = true; if (pDlgProgress) - lResult=GetIMDBDetails(pItem.get(), url, info2, bDirNames && info2.strContent.Equals("movies"), pDlgProgress, result == CNfoFile::COMBINED_NFO, bForce); + lResult=GetIMDBDetails(pItem.get(), url, info2, bDirNames && info2->Content() == CONTENT_MOVIES, pDlgProgress, result == CNfoFile::COMBINED_NFO, bForce); else - lResult=GetIMDBDetails(pItem.get(), url, info2, bDirNames && info2.strContent.Equals("movies"), NULL, result == CNfoFile::COMBINED_NFO, bForce); + lResult=GetIMDBDetails(pItem.get(), url, info2, bDirNames && info2->Content() == CONTENT_MOVIES, NULL, result == CNfoFile::COMBINED_NFO, bForce); - if (info2.strContent.Equals("tvshows")) + if (info2->Content() == CONTENT_TVSHOWS) { if (!bRefresh) { @@ -682,7 +664,7 @@ namespace VIDEO CFileItemList items; CLog::Log(LOGDEBUG, "%s - processing dir: %s", __FUNCTION__, strPath.c_str()); CDirectory::GetDirectory(strPath, items, g_settings.m_videoExtensions, true); - if (m_info.strContent.Equals("movies")) + if (m_info->Content() == CONTENT_MOVIES) items.Stack(); for (int i=0; i<items.Size(); ++i) @@ -976,7 +958,7 @@ namespace VIDEO return bMatched; } - long CVideoInfoScanner::AddMovie(CFileItem *pItem, const CStdString &content, CVideoInfoTag &movieDetails, int idShow) + long CVideoInfoScanner::AddMovie(CFileItem *pItem, const CONTENT_TYPE &content, CVideoInfoTag &movieDetails, int idShow) { // ensure our database is open (this can get called via other classes) if (!m_database.Open()) @@ -984,10 +966,11 @@ namespace VIDEO CLog::Log(LOGERROR, "%s - failed to open database", __FUNCTION__); return -1; } - CLog::Log(LOGDEBUG,"Adding new item to %s:%s", content.c_str(), pItem->m_strPath.c_str()); + CLog::Log(LOGDEBUG,"Adding new item to %s:%s", TranslateContent(content).c_str(), pItem->m_strPath.c_str()); long lResult=-1; + // add to all movies in the stacked set - if (content.Equals("movies")) + if (content == CONTENT_MOVIES) { // find local trailer first CStdString strTrailer = pItem->FindTrailer(); @@ -1014,7 +997,7 @@ namespace VIDEO } } } - else if (content.Equals("tvshows")) + else if (content == CONTENT_TVSHOWS) { if (pItem->m_bIsFolder) { @@ -1037,14 +1020,14 @@ namespace VIDEO } } } - else if (content.Equals("musicvideos")) + else if (content == CONTENT_MUSICVIDEOS) { m_database.SetDetailsForMusicVideo(pItem->m_strPath, movieDetails); } return lResult; } - long CVideoInfoScanner::AddMovieAndGetThumb(CFileItem *pItem, const CStdString &content, CVideoInfoTag &movieDetails, int idShow, bool bApplyToDir, bool bRefresh, CGUIDialogProgress* pDialog /* == NULL */) + long CVideoInfoScanner::AddMovieAndGetThumb(CFileItem *pItem, const CONTENT_TYPE &content, CVideoInfoTag &movieDetails, int idShow, bool bApplyToDir, bool bRefresh, CGUIDialogProgress* pDialog /* == NULL */) { long lResult = AddMovie(pItem, content, movieDetails, idShow); // get & save fanart image @@ -1066,7 +1049,7 @@ namespace VIDEO } CStdString strThumb = pItem->GetCachedVideoThumb(); - if (content.Equals("tvshows") && !pItem->m_bIsFolder && CFile::Exists(strThumb)) + if (content == CONTENT_TVSHOWS && !pItem->m_bIsFolder && CFile::Exists(strThumb)) { movieDetails.m_strFileNameAndPath = pItem->m_strPath; CFileItem item(movieDetails); @@ -1180,7 +1163,7 @@ namespace VIDEO // handle .nfo files CScraperUrl scrUrl; - SScraperInfo info(m_IMDB.GetScraperInfo()); + ScraperPtr info(m_IMDB.GetScraperInfo()); item.GetVideoInfoTag()->m_iEpisode = file->iEpisode; CNfoFile::NFOResult result = CheckForNFOFile(&item,false,info,scrUrl); if (result == CNfoFile::FULL_NFO) @@ -1192,7 +1175,7 @@ namespace VIDEO strTitle.Format("%s - %ix%i - %s",strShowTitle.c_str(),episodeDetails.m_iSeason,episodeDetails.m_iEpisode,episodeDetails.m_strTitle.c_str()); m_pObserver->OnSetTitle(strTitle); } - AddMovieAndGetThumb(&item,"tvshows",episodeDetails,idShow); + AddMovieAndGetThumb(&item,CONTENT_TVSHOWS,episodeDetails,idShow); continue; } @@ -1241,7 +1224,7 @@ namespace VIDEO } CFileItem item; item.m_strPath = file->strPath; - AddMovieAndGetThumb(&item,"tvshows",episodeDetails,idShow); + AddMovieAndGetThumb(&item,CONTENT_TVSHOWS,episodeDetails,idShow); } } if (g_guiSettings.GetBool("videolibrary.seasonthumbs")) @@ -1358,10 +1341,10 @@ namespace VIDEO return nfoFile; } - long CVideoInfoScanner::GetIMDBDetails(CFileItem *pItem, CScraperUrl &url, const SScraperInfo& info, bool bUseDirNames, CGUIDialogProgress* pDialog /* = NULL */, bool bCombined, bool bRefresh) + long CVideoInfoScanner::GetIMDBDetails(CFileItem *pItem, CScraperUrl &url, const ScraperPtr& scraper, bool bUseDirNames, CGUIDialogProgress* pDialog /* = NULL */, bool bCombined, bool bRefresh) { CVideoInfoTag movieDetails; - m_IMDB.SetScraperInfo(info); + m_IMDB.SetScraperInfo(scraper); movieDetails.m_strFileNameAndPath = pItem->m_strPath; if ( m_IMDB.GetDetails(url, movieDetails, pDialog) ) @@ -1378,7 +1361,7 @@ namespace VIDEO pDialog->Progress(); } - return AddMovieAndGetThumb(pItem, info.strContent, movieDetails, -1, bUseDirNames, bRefresh); + return AddMovieAndGetThumb(pItem, scraper->Content(), movieDetails, -1, bUseDirNames, bRefresh); } return -1; } @@ -1489,12 +1472,13 @@ namespace VIDEO } } - CNfoFile::NFOResult CVideoInfoScanner::CheckForNFOFile(CFileItem* pItem, bool bGrabAny, SScraperInfo& info, CScraperUrl& scrUrl) + CNfoFile::NFOResult CVideoInfoScanner::CheckForNFOFile(CFileItem* pItem, bool bGrabAny, ScraperPtr& info, CScraperUrl& scrUrl) { CStdString strNfoFile; - if (info.strContent.Equals("movies") || info.strContent.Equals("musicvideos") || (info.strContent.Equals("tvshows") && !pItem->m_bIsFolder)) + if (info->Content() == CONTENT_MOVIES || info->Content() == CONTENT_MUSICVIDEOS + || (info->Content() == CONTENT_TVSHOWS && !pItem->m_bIsFolder)) strNfoFile = GetnfoFile(pItem,bGrabAny); - if (info.strContent.Equals("tvshows") && pItem->m_bIsFolder) + if (info->Content() == CONTENT_TVSHOWS && pItem->m_bIsFolder) CUtil::AddFileToFolder(pItem->m_strPath,"tvshow.nfo",strNfoFile); CNfoFile::NFOResult result=CNfoFile::NO_NFO; @@ -1520,19 +1504,20 @@ namespace VIDEO CLog::Log(LOGDEBUG,"Found matching %s NFO file: %s", type.c_str(), strNfoFile.c_str()); if (result == CNfoFile::FULL_NFO) { - if (info.strContent.Equals("tvshows")) - info.strPath = m_nfoReader.m_strScraper; + if (info->Content() == CONTENT_TVSHOWS) + info = m_nfoReader.GetScraperInfo(); } else if (result != CNfoFile::NO_NFO) { CScraperUrl url(m_nfoReader.m_strImDbUrl); scrUrl = url; - CLog::Log(LOGDEBUG, "scraper: Fetching url '%s' using %s scraper (file: '%s', content: '%s', language: '%s', date: '%s', framework: '%s')", - scrUrl.m_url[0].m_url.c_str(), info.strTitle.c_str(), info.strPath.c_str(), info.strContent.c_str(), info.strLanguage.c_str(), info.strDate.c_str(), info.strFramework.c_str()); + ScraperPtr info(m_nfoReader.GetScraperInfo()); + CLog::Log(LOGDEBUG, "scraper: Fetching url '%s' using %s scraper (content: '%s')", + scrUrl.m_url[0].m_url.c_str(), info->Name().c_str(), TranslateContent(info->Content()).c_str()); scrUrl.strId = m_nfoReader.m_strImDbNr; - info.strPath = m_nfoReader.m_strScraper; + info = m_nfoReader.GetScraperInfo(); if (result == CNfoFile::COMBINED_NFO) m_nfoReader.GetDetails(*pItem->GetVideoInfoTag()); } diff --git a/xbmc/VideoInfoScanner.h b/xbmc/VideoInfoScanner.h index 78fca539ff..f6b6ca340d 100644 --- a/xbmc/VideoInfoScanner.h +++ b/xbmc/VideoInfoScanner.h @@ -21,7 +21,7 @@ */ #include "utils/Thread.h" #include "VideoDatabase.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "NfoFile.h" #include "IMDB.h" #include "DateTime.h" @@ -32,10 +32,12 @@ namespace VIDEO { typedef struct SScanSettings { + SScanSettings() { parent_name = parent_name_root = noupdate = exclude = false; recurse = -1;} bool parent_name; /* use the parent dirname as name of lookup */ bool parent_name_root; /* use the name of directory where scan started as name for files in that dir */ int recurse; /* recurse into sub folders (indicate levels) */ bool noupdate; /* exclude from update library function */ + bool exclude; /* exclude this path from scraping */ } SScanSettings; typedef struct SEpisode @@ -68,7 +70,7 @@ namespace VIDEO public: CVideoInfoScanner(); virtual ~CVideoInfoScanner(); - void Start(const CStdString& strDirectory, const SScraperInfo& info, const SScanSettings& settings, bool bUpdateAll); + void Start(const CStdString& strDirectory, const ADDON::ScraperPtr& info, const SScanSettings& settings, bool bUpdateAll); bool IsScanning(); void Stop(); void SetObserver(IVideoInfoScannerObserver* pObserver); @@ -76,16 +78,16 @@ namespace VIDEO void EnumerateSeriesFolder(CFileItem* item, EPISODES& episodeList); bool ProcessItemNormal(CFileItemPtr item, EPISODES& episodeList, CStdString regexp); bool ProcessItemByDate(CFileItemPtr item, EPISODES& eipsodeList, CStdString regexp); - long AddMovie(CFileItem *pItem, const CStdString &content, CVideoInfoTag &movieDetails, int idShow = -1); - long AddMovieAndGetThumb(CFileItem *pItem, const CStdString &content, CVideoInfoTag &movieDetails, int idShow, bool bApplyToDir=false, bool bRefresh=false, CGUIDialogProgress* pDialog = NULL); + long AddMovie(CFileItem *pItem, const CONTENT_TYPE &content, CVideoInfoTag &movieDetails, int idShow = -1); + long AddMovieAndGetThumb(CFileItem *pItem, const CONTENT_TYPE &content, CVideoInfoTag &movieDetails, int idShow, bool bApplyToDir=false, bool bRefresh=false, CGUIDialogProgress* pDialog = NULL); bool OnProcessSeriesFolder(IMDB_EPISODELIST& episodes, EPISODES& files, int idShow, const CStdString& strShowTitle, CGUIDialogProgress* pDlgProgress = NULL); static CStdString GetnfoFile(CFileItem *item, bool bGrabAny=false); - long GetIMDBDetails(CFileItem *pItem, CScraperUrl &url, const SScraperInfo& info, bool bUseDirNames=false, CGUIDialogProgress* pDialog=NULL, bool bCombined=false, bool bRefresh=false); - bool RetrieveVideoInfo(CFileItemList& items, bool bDirNames, const SScraperInfo& info, bool bRefresh=false, CScraperUrl *pURL=NULL, CGUIDialogProgress* pDlgProgress = NULL, bool ignoreNfo=false); + long GetIMDBDetails(CFileItem *pItem, CScraperUrl &url, const ADDON::ScraperPtr &scraper, bool bUseDirNames=false, CGUIDialogProgress* pDialog=NULL, bool bCombined=false, bool bRefresh=false); + bool RetrieveVideoInfo(CFileItemList& items, bool bDirNames, const ADDON::ScraperPtr &info, bool bRefresh=false, CScraperUrl *pURL=NULL, CGUIDialogProgress* pDlgProgress = NULL, bool ignoreNfo=false); static void ApplyIMDBThumbToFolder(const CStdString &folder, const CStdString &imdbThumb); static int GetPathHash(const CFileItemList &items, CStdString &hash); static bool DownloadFailed(CGUIDialogProgress* pDlgProgress); - CNfoFile::NFOResult CheckForNFOFile(CFileItem* pItem, bool bGrabAny, SScraperInfo& info, CScraperUrl& scrUrl); + CNfoFile::NFOResult CheckForNFOFile(CFileItem* pItem, bool bGrabAny, ADDON::ScraperPtr& scraper, CScraperUrl& scrUrl); CIMDB m_IMDB; /*! \brief Fetch thumbs for seasons for a given show Fetches and caches local season thumbs of the form season##.tbn and season-all.tbn for the current show, @@ -114,7 +116,7 @@ namespace VIDEO bool m_bClean; CStdString m_strStartDir; CVideoDatabase m_database; - SScraperInfo m_info; + ADDON::ScraperPtr m_info; std::map<CStdString,SScanSettings> m_pathsToScan; std::set<CStdString> m_pathsToCount; std::vector<int> m_pathsToClean; diff --git a/xbmc/addons/include/NOTE b/xbmc/addons/include/NOTE new file mode 100644 index 0000000000..a38d4328c3 --- /dev/null +++ b/xbmc/addons/include/NOTE @@ -0,0 +1,9 @@ +NOTE: + +This directory contains independent Headers to build Add-on's +without the whole XBMC source tree. The Add-on itself can add +this headers to his source tree without dependencies to any +XBMC related classes or functions. + +Also this headers are never changed without a API Version +change. diff --git a/xbmc/addons/include/xbmc_addon_cpp_dll.h b/xbmc/addons/include/xbmc_addon_cpp_dll.h new file mode 100644 index 0000000000..a193a76c9e --- /dev/null +++ b/xbmc/addons/include/xbmc_addon_cpp_dll.h @@ -0,0 +1,171 @@ +#ifndef __XBMC_ADDON_CPP_H__ +#define __XBMC_ADDON_CPP_H__ + +#include "xbmc_addon_dll.h" + +#include <vector> +#include <string.h> +#include <stdlib.h> + +class DllSetting +{ +public: + enum SETTING_TYPE { NONE=0, CHECK, SPIN }; + + DllSetting(SETTING_TYPE t, const char *n, const char *l) + { + id = NULL; + label = NULL; + if (n) + { + id = new char[strlen(n)+1]; + strcpy(id, n); + } + if (l) + { + label = new char[strlen(l)+1]; + strcpy(label, l); + } + current = 0; + type = t; + } + + DllSetting(const DllSetting &rhs) // copy constructor + { + id = NULL; + label = NULL; + if (rhs.id) + { + id = new char[strlen(rhs.id)+1]; + strcpy(id, rhs.id); + } + if (rhs.label) + { + label = new char[strlen(rhs.label)+1]; + strcpy(label, rhs.label); + } + current = rhs.current; + type = rhs.type; + for (unsigned int i = 0; i < rhs.entry.size(); i++) + { + char *lab = new char[strlen(rhs.entry[i]) + 1]; + strcpy(lab, rhs.entry[i]); + entry.push_back(lab); + } + } + + ~DllSetting() + { + delete[] id; + delete[] label; + for (unsigned int i=0; i < entry.size(); i++) + delete[] entry[i]; + } + + void AddEntry(const char *label) + { + if (!label || type != SPIN) return; + char *lab = new char[strlen(label) + 1]; + strcpy(lab, label); + entry.push_back(lab); + } + + // data members + SETTING_TYPE type; + char* id; + char* label; + int current; + std::vector<const char *> entry; +}; + +class DllUtils +{ +public: + + static unsigned int VecToStruct(std::vector<DllSetting> &vecSet, StructSetting*** sSet) + { + *sSet = NULL; + if(vecSet.size() == 0) + return 0; + + unsigned int uiElements=0; + + *sSet = (StructSetting**)malloc(vecSet.size()*sizeof(StructSetting*)); + for(unsigned int i=0;i<vecSet.size();i++) + { + (*sSet)[i] = NULL; + (*sSet)[i] = (StructSetting*)malloc(sizeof(StructSetting)); + (*sSet)[i]->id = NULL; + (*sSet)[i]->label = NULL; + uiElements++; + + if (vecSet[i].id && vecSet[i].label) + { + (*sSet)[i]->id = strdup(vecSet[i].id); + (*sSet)[i]->label = strdup(vecSet[i].label); + (*sSet)[i]->type = vecSet[i].type; + (*sSet)[i]->current = vecSet[i].current; + (*sSet)[i]->entry_elements = 0; + (*sSet)[i]->entry = NULL; + if(vecSet[i].type == DllSetting::SPIN && vecSet[i].entry.size() > 0) + { + (*sSet)[i]->entry = (char**)malloc(vecSet[i].entry.size()*sizeof(char**)); + for(unsigned int j=0;j<vecSet[i].entry.size();j++) + { + if(strlen(vecSet[i].entry[j]) > 0) + { + (*sSet)[i]->entry[j] = strdup(vecSet[i].entry[j]); + (*sSet)[i]->entry_elements++; + } + } + } + } + } + return uiElements; + } + + static void StructToVec(unsigned int iElements, StructSetting*** sSet, std::vector<DllSetting> *vecSet) + { + if(iElements == 0) + return; + + vecSet->clear(); + for(unsigned int i=0;i<iElements;i++) + { + DllSetting vSet((DllSetting::SETTING_TYPE)(*sSet)[i]->type, (*sSet)[i]->id, (*sSet)[i]->label); + if((*sSet)[i]->type == DllSetting::SPIN) + { + for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++) + { + vSet.AddEntry((*sSet)[i]->entry[j]); + } + } + vSet.current = (*sSet)[i]->current; + vecSet->push_back(vSet); + } + } + + static void FreeStruct(unsigned int iElements, StructSetting*** sSet) + { + if(iElements == 0) + return; + + for(unsigned int i=0;i<iElements;i++) + { + if((*sSet)[i]->type == DllSetting::SPIN) + { + for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++) + { + free((*sSet)[i]->entry[j]); + } + free((*sSet)[i]->entry); + } + free((*sSet)[i]->id); + free((*sSet)[i]->label); + free((*sSet)[i]); + } + free(*sSet); + } +}; + +#endif diff --git a/xbmc/addons/include/xbmc_addon_dll.h b/xbmc/addons/include/xbmc_addon_dll.h new file mode 100644 index 0000000000..b973b21154 --- /dev/null +++ b/xbmc/addons/include/xbmc_addon_dll.h @@ -0,0 +1,46 @@ +#ifndef __XBMC_ADDON_H__ +#define __XBMC_ADDON_H__ + +#ifdef _WIN32 +#include <windows.h> +#else +#ifndef __cdecl +#define __cdecl +#endif +#ifndef __declspec +#define __declspec(X) +#endif +#endif + +extern "C" +{ + enum ADDON_STATUS + { + STATUS_OK, + STATUS_LOST_CONNECTION, + STATUS_NEED_RESTART, + STATUS_NEED_SETTINGS, + STATUS_UNKNOWN + }; + + typedef struct + { + int type; + char* id; + char* label; + int current; + char** entry; + unsigned int entry_elements; + } StructSetting; + + ADDON_STATUS __declspec(dllexport) Create(void *callbacks, void* props); + void __declspec(dllexport) Destroy(); + ADDON_STATUS __declspec(dllexport) GetStatus(); + bool __declspec(dllexport) HasSettings(); + unsigned int __declspec(dllexport) GetSettings(StructSetting ***sSet); + ADDON_STATUS __declspec(dllexport) SetSetting(const char *settingName, const void *settingValue); + void __declspec(dllexport) Remove(); + void __declspec(dllexport) FreeSettings(); +}; + +#endif diff --git a/xbmc/addons/include/xbmc_scr_dll.h b/xbmc/addons/include/xbmc_scr_dll.h new file mode 100644 index 0000000000..554c42e977 --- /dev/null +++ b/xbmc/addons/include/xbmc_scr_dll.h @@ -0,0 +1,26 @@ +#ifndef __XBMC_SCR_H__ +#define __XBMC_SCR_H__ + +#include "xbmc_addon_dll.h" +#include "xbmc_scr_types.h" + +extern "C" +{ + + // Functions that your visualisation must implement + void Start(); + void Render(); + void Stop(); + void GetInfo(SCR_INFO* pInfo); + + // function to export the above structure to XBMC + void __declspec(dllexport) get_addon(struct ScreenSaver* pScr) + { + pScr->Start = Start; + pScr->Render = Render; + pScr->Stop = Stop; + pScr->GetInfo = GetInfo; + }; +}; + +#endif diff --git a/xbmc/screensavers/ScreenSaverFactory.h b/xbmc/addons/include/xbmc_scr_types.h index 81fc4ea1f9..e1d0bbac51 100644 --- a/xbmc/screensavers/ScreenSaverFactory.h +++ b/xbmc/addons/include/xbmc_scr_types.h @@ -1,6 +1,6 @@ #pragma once /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2009 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -19,12 +19,35 @@ * http://www.gnu.org/copyleft/gpl.html * */ -#include "ScreenSaver.h" -class CScreenSaverFactory +#ifndef __SCREENSAVER_TYPES_H__ +#define __SCREENSAVER_TYPES_H__ + +extern "C" { -public: - CScreenSaverFactory(); - virtual ~CScreenSaverFactory(); - CScreenSaver* LoadScreenSaver(const CStdString& strScr) const; -}; + struct SCR_INFO + { + int dummy; + }; + + struct SCR_PROPS + { + void *device; + int x; + int y; + int width; + int height; + float pixelRatio; + char *name; + }; + + struct ScreenSaver + { + void (__cdecl* Start) (); + void (__cdecl* Render) (); + void (__cdecl* Stop) (); + void (__cdecl* GetInfo)(SCR_INFO *info); + }; +} + +#endif // __SCREENSAVER_TYPES_H__ diff --git a/xbmc/addons/include/xbmc_vis_dll.h b/xbmc/addons/include/xbmc_vis_dll.h new file mode 100644 index 0000000000..60aef0bab1 --- /dev/null +++ b/xbmc/addons/include/xbmc_vis_dll.h @@ -0,0 +1,37 @@ +#ifndef __XBMC_VIS_H__ +#define __XBMC_VIS_H__ + +#include "xbmc_addon_dll.h" +#include "xbmc_vis_types.h" + +extern "C" +{ + // Functions that your visualisation must implement + void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); + void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); + void Render(); + void Stop(); + bool OnAction(long action, const void *param); + void GetInfo(VIS_INFO* pInfo); + unsigned int GetPresets(char ***presets); + unsigned GetPreset(); + unsigned int GetSubModules(char ***presets); + bool IsLocked(); + + // function to export the above structure to XBMC + void __declspec(dllexport) get_addon(struct Visualisation* pVisz) + { + pVisz->Start = Start; + pVisz->AudioData = AudioData; + pVisz->Render = Render; + pVisz->Stop = Stop; + pVisz->OnAction = OnAction; + pVisz->GetInfo = GetInfo; + pVisz->GetPresets = GetPresets; + pVisz->GetPreset = GetPreset; + pVisz->GetSubModules = GetSubModules; + pVisz->IsLocked = IsLocked; + }; +}; + +#endif diff --git a/xbmc/addons/include/xbmc_vis_types.h b/xbmc/addons/include/xbmc_vis_types.h new file mode 100644 index 0000000000..3c6f904d8c --- /dev/null +++ b/xbmc/addons/include/xbmc_vis_types.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +/* + Common data structures shared between XBMC and XBMC's visualisations + */ + +#ifndef __VISUALISATION_TYPES_H__ +#define __VISUALISATION_TYPES_H__ +#include <cstddef> + +extern "C" +{ + struct VIS_INFO + { + int bWantsFreq; + int iSyncDelay; + }; + + struct VIS_PROPS + { + void *device; + int x; + int y; + int width; + int height; + float pixelRatio; + const char *name; + const char *presets; + const char *profile; + const char *submodule; + }; + + enum VIS_ACTION + { + VIS_ACTION_NONE = 0, + VIS_ACTION_NEXT_PRESET, + VIS_ACTION_PREV_PRESET, + VIS_ACTION_LOAD_PRESET, + VIS_ACTION_RANDOM_PRESET, + VIS_ACTION_LOCK_PRESET, + VIS_ACTION_RATE_PRESET_PLUS, + VIS_ACTION_RATE_PRESET_MINUS, + VIS_ACTION_UPDATE_ALBUMART, + VIS_ACTION_UPDATE_TRACK + }; + + class VisTrack + { + public: + VisTrack() + { + title = artist = album = albumArtist = NULL; + genre = comment = lyrics = reserved1 = reserved2 = NULL; + trackNumber = discNumber = duration = year = 0; + rating = 0; + reserved3 = reserved4 = 0; + } + + const char *title; + const char *artist; + const char *album; + const char *albumArtist; + const char *genre; + const char *comment; + const char *lyrics; + const char *reserved1; + const char *reserved2; + + int trackNumber; + int discNumber; + int duration; + int year; + char rating; + int reserved3; + int reserved4; + }; + + struct Visualisation + { + void (__cdecl* Start)(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); + void (__cdecl* AudioData)(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); + void (__cdecl* Render) (); + void (__cdecl* Stop)(); + void (__cdecl* GetInfo)(VIS_INFO *info); + bool (__cdecl* OnAction)(long flags, const void *param); + int (__cdecl* HasPresets)(); + unsigned int (__cdecl *GetPresets)(char ***presets); + unsigned int (__cdecl *GetPreset)(); + unsigned int (__cdecl *GetSubModules)(char ***modules); + bool (__cdecl* IsLocked)(); + }; +} + +#endif //__VISUALISATION_TYPES_H__ diff --git a/xbmc/karaoke/karaokewindowbackground.cpp b/xbmc/karaoke/karaokewindowbackground.cpp index 376059a245..49c598f837 100644 --- a/xbmc/karaoke/karaokewindowbackground.cpp +++ b/xbmc/karaoke/karaokewindowbackground.cpp @@ -115,7 +115,7 @@ bool CKaraokeWindowBackground::OnMessage(CGUIMessage & message) case GUI_MSG_GET_VISUALISATION: if ( m_currentMode == BACKGROUND_VISUALISATION ) - message.SetPointer( m_VisControl->GetVisualisation() ); + return m_VisControl->OnMessage(message); break; case GUI_MSG_VISUALISATION_ACTION: diff --git a/xbmc/lib/libPython/xbmcmodule/PythonSettings.cpp b/xbmc/lib/libPython/xbmcmodule/PythonSettings.cpp index 770283d417..e3ff82a31e 100644 --- a/xbmc/lib/libPython/xbmcmodule/PythonSettings.cpp +++ b/xbmc/lib/libPython/xbmcmodule/PythonSettings.cpp @@ -21,7 +21,8 @@ #include "PythonSettings.h" #include "pyutil.h" -#include "GUIDialogPluginSettings.h" +#include "AddonManager.h" +#include "GUIDialogAddonSettings.h" #ifndef __GNUC__ #pragma code_seg("PY_TEXT") @@ -34,6 +35,9 @@ extern "C" { #endif +using ADDON::AddonPtr; +using ADDON::CAddonMgr; + namespace PYXBMC { PyObject* Settings_New(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -43,8 +47,8 @@ namespace PYXBMC self = (Settings*)type->tp_alloc(type, 0); if (!self) return NULL; - static const char *keywords[] = { "path", NULL }; - char *cScriptPath = NULL; + static const char *keywords[] = { "uuid", NULL }; + char *cScriptUUID = NULL; // parse arguments if (!PyArg_ParseTupleAndKeywords( @@ -52,33 +56,35 @@ namespace PYXBMC kwds, (char*)"s", (char**)keywords, - &cScriptPath + &cScriptUUID )) { Py_DECREF(self); return NULL; }; - if (!CScriptSettings::SettingsExist(cScriptPath)) + AddonPtr addon; + if (CAddonMgr::Get()->GetAddon(ADDON::ADDON_SCRIPT, CStdString(cScriptUUID), addon)) + { + PyErr_SetString(PyExc_Exception, "Could not get AddonPtr!"); + return NULL; + } + + self->pAddon = addon.get(); + if (!self->pAddon->HasSettings()) { PyErr_SetString(PyExc_Exception, "No settings.xml file could be found!"); return NULL; } - self->pSettings = new CScriptSettings(); - self->pSettings->Clear(); - self->pSettings->Load(cScriptPath); + self->pAddon->LoadSettings(); return (PyObject*)self; } void Settings_Dealloc(Settings* self) { - if (self->pSettings) - { - self->pSettings->Clear(); - delete self->pSettings; - } + //TODO is there anything that should be freed here, other than the AddonPtr? self->ob_type->tp_free((PyObject*)self); } @@ -107,7 +113,7 @@ namespace PYXBMC return NULL; }; - return Py_BuildValue((char*)"s", self->pSettings->Get(id).c_str()); + return Py_BuildValue((char*)"s", self->pAddon->GetSetting(id).c_str()); } PyDoc_STRVAR(setSetting__doc__, @@ -146,8 +152,8 @@ namespace PYXBMC return NULL; } - self->pSettings->Set(id, value); - self->pSettings->Save(); + self->pAddon->UpdateSetting(id, "", value); + self->pAddon->SaveSettings(); Py_INCREF(Py_None); return Py_None; @@ -162,11 +168,11 @@ namespace PYXBMC PyObject* Settings_OpenSettings(Settings *self, PyObject *args, PyObject *kwds) { // show settings dialog - CStdString path = self->pSettings->getPath(); - CGUIDialogPluginSettings::ShowAndGetInput(path); + AddonPtr addon(self->pAddon); + CGUIDialogAddonSettings::ShowAndGetInput(addon); // reload settings - self->pSettings->Load(path); + self->pAddon->LoadSettings(); Py_INCREF(Py_None); return Py_None; @@ -179,20 +185,21 @@ namespace PYXBMC {NULL, NULL, 0, NULL} }; + //FIXME!! incomplete docs PyDoc_STRVAR(settings__doc__, "Settings class.\n" "\n" - "Settings(path) -- Creates a new Settings class.\n" + "Settings(uuid) -- Creates a new Settings class.\n" "\n" - "path : string - path to script. (eg special://home/scripts/Apple Movie Trailers)\n" + "uuid : string - UUID of this script.\n" "\n" - "*Note, settings folder structure is eg(resources/settings.xml)\n" + "*Note, settings folder structure must match (resources/settings.xml)\n" "\n" " You can use the above as keywords for arguments and skip certain optional arguments.\n" " Once you use a keyword, all following arguments require the keyword.\n" "\n" "example:\n" - " - self.Settings = xbmc.Settings(path=os.getcwd())\n"); + " - self.Settings = xbmc.Settings(uuid=os.uuid())\n"); // Restore code and data sections to normal. #ifndef __GNUC__ diff --git a/xbmc/lib/libPython/xbmcmodule/PythonSettings.h b/xbmc/lib/libPython/xbmcmodule/PythonSettings.h index 10302b73c3..72f5cdcb00 100644 --- a/xbmc/lib/libPython/xbmcmodule/PythonSettings.h +++ b/xbmc/lib/libPython/xbmcmodule/PythonSettings.h @@ -37,7 +37,8 @@ #else #include "lib/libPython/Python/Include/Python.h" #endif -#include "ScriptSettings.h" + +#include "utils/IAddon.h" #ifdef __cplusplus extern "C" { @@ -47,7 +48,7 @@ namespace PYXBMC { typedef struct { PyObject_HEAD - CScriptSettings* pSettings; + ADDON::IAddon* pAddon; } Settings; extern PyTypeObject Settings_Type; diff --git a/xbmc/lib/libPython/xbmcmodule/xbmcplugin.cpp b/xbmc/lib/libPython/xbmcmodule/xbmcplugin.cpp index 1fc5cf7191..76ebac2e00 100644 --- a/xbmc/lib/libPython/xbmcmodule/xbmcplugin.cpp +++ b/xbmc/lib/libPython/xbmcmodule/xbmcplugin.cpp @@ -21,15 +21,14 @@ #include "FileSystem/PluginDirectory.h" #include "listitem.h" -#include "PluginSettings.h" #include "FileItem.h" -#include "GUIDialogPluginSettings.h" // include for constants #include "pyutil.h" using namespace std; using namespace XFILE; +using namespace ADDON; #ifndef __GNUC__ #pragma code_seg("PY_TEXT") @@ -292,55 +291,61 @@ namespace PYXBMC } PyDoc_STRVAR(getSetting__doc__, - "getSetting(id) -- Returns the value of a setting as a string.\n" + "getSetting(handle, id) -- Returns the value of a setting as a string.\n" "\n" + "handle : integer - handle the plugin was started with.\n" "id : string - id of the setting that the module needs to access.\n" "\n" "*Note, You can use the above as a keyword.\n" "\n" "example:\n" - " - apikey = xbmcplugin.getSetting('apikey')\n"); + " - apikey = xbmcplugin.getSetting(int(sys.argv[1]), 'apikey')\n"); PyObject* XBMCPLUGIN_GetSetting(PyObject *self, PyObject *args, PyObject *kwds) { - static const char *keywords[] = { "id", NULL }; + static const char *keywords[] = { "handle", "id", NULL }; + int handle = -1; char *id; if (!PyArg_ParseTupleAndKeywords( args, kwds, - (char*)"s", + (char*)"is", (char**)keywords, + &handle, &id )) { return NULL; }; - return Py_BuildValue((char*)"s", g_currentPluginSettings.Get(id).c_str()); + return Py_BuildValue((char*)"s", XFILE::CPluginDirectory::GetSetting(handle, id).c_str()); } PyDoc_STRVAR(setSetting__doc__, - "setSetting(id, value) -- Sets a plugin setting for the current running plugin.\n" + "setSetting(handle, id, value) -- Sets a plugin setting for the current running plugin.\n" "\n" + "handle : integer - handle the plugin was started with.\n" "id : string - id of the setting that the module needs to access.\n" "value : string or unicode - value of the setting.\n" "\n" "*Note, You can use the above as keywords for arguments.\n" "\n" "example:\n" - " - xbmcplugin.setSetting(id='username', value='teamxbmc')\n"); + " - xbmcplugin.setSetting(int(sys.argv[1]), id='username', value='teamxbmc')\n"); PyObject* XBMCPLUGIN_SetSetting(PyObject *self, PyObject *args, PyObject *kwds) { - static const char *keywords[] = { "id", "value", NULL }; + static const char *keywords[] = { "handle", "id", "value" }; + int handle = -1; char *id; PyObject *pValue = NULL; if (!PyArg_ParseTupleAndKeywords( args, kwds, - (char*)"sO", + (char*)"isO", (char**)keywords, + &handle, &id, &pValue )) @@ -350,13 +355,9 @@ namespace PYXBMC CStdString value; if (!id || !PyXBMCGetUnicodeString(value, pValue, 1)) - { - PyErr_SetString(PyExc_ValueError, "Invalid id or value!"); return NULL; - } - g_currentPluginSettings.Set(id, value); - g_currentPluginSettings.Save(); + XFILE::CPluginDirectory::SetSetting(handle, id, value); Py_INCREF(Py_None); return Py_None; @@ -449,7 +450,7 @@ namespace PYXBMC "*Note, You can use the above as keywords for arguments.\n" "\n" "example:\n" - " - xbmcplugin.setPluginFanart(int(sys.argv[1]), 'special://home/plugins/video/Apple movie trailers II/fanart.png', color2='0xFFFF3300')\n"); + " - xbmcplugin.setPluginFanart(int(sys.argv[1]), 'special://home/addons/plugins/video/Apple movie trailers II/fanart.png', color2='0xFFFF3300')\n"); PyObject* XBMCPLUGIN_SetPluginFanart(PyTypeObject *type, PyObject *args, PyObject *kwds) { @@ -533,61 +534,6 @@ namespace PYXBMC return Py_None; } - PyDoc_STRVAR(openSettings__doc__, - "openSettings(url[, reload]) -- Opens this plugins settings.\n" - "\n" - "url : string or unicode - url of plugin. (plugin://pictures/picasa/)\n" - "reload : [opt] bool - reload language strings and settings (default=True)\n" - "\n" - "*Note, You can use the above as keywords for arguments and skip certain optional arguments.\n" - " Once you use a keyword, all following arguments require the keyword.\n" - " reload is only necessary if calling openSettings() from the plugin.\n" - "\n" - "example:\n" - " - xbmcplugin.openSettings(url=sys.argv[0])\n"); - - PyObject* XBMCPLUGIN_OpenSettings(PyTypeObject *type, PyObject *args, PyObject *kwds) - { - static const char *keywords[] = { "url", "reload", NULL }; - PyObject *pUrl = NULL; - char bReload = true; - // parse arguments to constructor - if (!PyArg_ParseTupleAndKeywords( - args, - kwds, - (char*)"O|b", - (char**)keywords, - &pUrl, - &bReload - )) - { - return NULL; - }; - - CStdString url; - if (!pUrl || (pUrl && !PyXBMCGetUnicodeString(url, pUrl, 1))) - return NULL; - - if (!CPluginSettings::SettingsExist(url)) - { - PyErr_SetString(PyExc_Exception, "No settings.xml file could be found!"); - return NULL; - } - - CURL cUrl(url); - CGUIDialogPluginSettings::ShowAndGetInput(cUrl); - - // reload plugin settings & strings - if (bReload) - { - g_currentPluginSettings.Load(cUrl); - XFILE::CPluginDirectory::LoadPluginStrings(cUrl); - } - - Py_INCREF(Py_None); - return Py_None; - } - // define c functions to be used in python here PyMethodDef pluginMethods[] = { {(char*)"addDirectoryItem", (PyCFunction)XBMCPLUGIN_AddDirectoryItem, METH_VARARGS|METH_KEYWORDS, addDirectoryItem__doc__}, @@ -601,7 +547,6 @@ namespace PYXBMC {(char*)"setPluginCategory", (PyCFunction)XBMCPLUGIN_SetPluginCategory, METH_VARARGS|METH_KEYWORDS, setPluginCategory__doc__}, {(char*)"setPluginFanart", (PyCFunction)XBMCPLUGIN_SetPluginFanart, METH_VARARGS|METH_KEYWORDS, setPluginFanart__doc__}, {(char*)"setProperty", (PyCFunction)XBMCPLUGIN_SetProperty, METH_VARARGS|METH_KEYWORDS, setProperty__doc__}, - {(char*)"openSettings", (PyCFunction)XBMCPLUGIN_OpenSettings, METH_VARARGS|METH_KEYWORDS, openSettings__doc__}, {NULL, NULL, 0, NULL} }; diff --git a/xbmc/lib/libhttpapi/XBMChttp.cpp b/xbmc/lib/libhttpapi/XBMChttp.cpp index b8a10b9abe..cd0db87b4c 100644 --- a/xbmc/lib/libhttpapi/XBMChttp.cpp +++ b/xbmc/lib/libhttpapi/XBMChttp.cpp @@ -28,6 +28,7 @@ #include "Picture.h" #include "MusicInfoTagLoaderFactory.h" #include "utils/MusicInfoScraper.h" +#include "utils/AddonManager.h" #include "MusicDatabase.h" #include "GUIUserMessages.h" #include "GUIWindowSlideShow.h" @@ -61,6 +62,7 @@ using namespace MUSIC_GRABBER; using namespace XFILE; using namespace PLAYLIST; using namespace MUSIC_INFO; +using namespace ADDON; #define XML_MAX_INNERTEXT_SIZE 256 #define MAX_PARAS 20 @@ -2250,9 +2252,14 @@ int CXbmcHttp::xbmcLookupAlbum(int numParas, CStdString paras[]) CStdString albums="", album, artist="", tmp; double relevance; bool rel = false; - SScraperInfo info; - info.strContent = "albums"; - info.strPath = g_guiSettings.GetString("musiclibrary.defaultscraper"); + AddonPtr addon; + if (!CAddonMgr::Get()->GetDefault(ADDON_SCRAPER, addon, CONTENT_ALBUMS)) + return -1; + ScraperPtr info = boost::dynamic_pointer_cast<CScraper>(addon); + if (!info) + return -1; + info->m_pathContent = CONTENT_ALBUMS; + CMusicInfoScraper scraper(info); if (numParas<1) @@ -2318,7 +2325,7 @@ int CXbmcHttp::xbmcChooseAlbum(int numParas, CStdString paras[]) { CMusicAlbumInfo musicInfo;//("", "") ; XFILE::CFileCurl http; - SScraperInfo info; // TODO - WTF is this code supposed to do? + ScraperPtr info; // TODO - WTF is this code supposed to do? if (musicInfo.Load(http,info)) { if (musicInfo.GetAlbum().thumbURL.m_url.size() > 0) diff --git a/xbmc/screensavers/DllScreenSaver.h b/xbmc/screensavers/DllScreenSaver.h index c481b916fe..4512a5f361 100644 --- a/xbmc/screensavers/DllScreenSaver.h +++ b/xbmc/screensavers/DllScreenSaver.h @@ -19,38 +19,12 @@ * http://www.gnu.org/copyleft/gpl.html * */ -#include "DynamicDll.h" -struct SCR_INFO -{ - int dummy; -}; +#include "../DllAddon.h" +#include "../addons/include/xbmc_scr_types.h" -struct ScreenSaver +class DllScreenSaver : public DllAddon<ScreenSaver, SCR_PROPS> { -public: -#ifdef HAS_DX - void (__cdecl* Create)(LPDIRECT3DDEVICE9 pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float pixelRatio); -#else - void (__cdecl* Create)(void* pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float pixelRatio); -#endif - void (__cdecl* Start) (); - void (__cdecl* Render) (); - void (__cdecl* Stop) (); - void (__cdecl* GetInfo)(SCR_INFO *info); + // this is populated via Macro calls in DllAddon.h }; -class DllScreensaverInterface -{ -public: - void GetModule(struct ScreenSaver* pScr); -}; - -class DllScreensaver : public DllDynamic, DllScreensaverInterface -{ - DECLARE_DLL_WRAPPER_TEMPLATE(DllScreensaver) - DEFINE_METHOD1(void, GetModule, (struct ScreenSaver* p1)) - BEGIN_METHOD_RESOLVE() - RESOLVE_METHOD_RENAME(get_module,GetModule) - END_METHOD_RESOLVE() -}; diff --git a/xbmc/screensavers/Makefile.in b/xbmc/screensavers/Makefile.in index 232772c506..664041556b 100644 --- a/xbmc/screensavers/Makefile.in +++ b/xbmc/screensavers/Makefile.in @@ -8,7 +8,7 @@ ifeq ($(findstring osx,$(ARCH)), osx) CXXFLAGS+=-isysroot /Developer/SDKs/MacOSX10.4u.sdk -mmacosx-version-min=10.4 endif -SRCS=ScreenSaver.cpp ScreenSaverFactory.cpp +SRCS=ScreenSaver.cpp LIB=screensaver.a include ../../Makefile.include diff --git a/xbmc/screensavers/ScreenSaver.cpp b/xbmc/screensavers/ScreenSaver.cpp index aae316e8e1..3bcb73c814 100644 --- a/xbmc/screensavers/ScreenSaver.cpp +++ b/xbmc/screensavers/ScreenSaver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2009 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -18,68 +18,29 @@ * http://www.gnu.org/copyleft/gpl.html * */ -// Screensaver.cpp: implementation of the CScreenSaver class. -// -////////////////////////////////////////////////////////////////////// - #include "ScreenSaver.h" -#include "Settings.h" -#include "WindowingFactory.h" - -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// - -CScreenSaver::CScreenSaver(struct ScreenSaver* pScr, DllScreensaver* pDll, const CStdString& strScreenSaverName) - : m_pScr(pScr) - , m_pDll(pDll) - , m_strScreenSaverName(strScreenSaverName) -{} - -CScreenSaver::~CScreenSaver() -{ -} - -void CScreenSaver::Create() -{ - // pass it the screen width,height - // and the name of the screensaver - int iWidth = g_graphicsContext.GetWidth(); - int iHeight = g_graphicsContext.GetHeight(); - - char szTmp[129]; - sprintf(szTmp, "scr create:%ix%i %s\n", iWidth, iHeight, m_strScreenSaverName.c_str()); - OutputDebugString(szTmp); - - float pixelRatio = g_settings.m_ResInfo[g_graphicsContext.GetVideoResolution()].fPixelRatio; -#ifdef HAS_DX - m_pScr->Create(g_Windowing.Get3DDevice(), iWidth, iHeight, m_strScreenSaverName.c_str(), pixelRatio); -#else - m_pScr->Create(0, iWidth, iHeight, m_strScreenSaverName.c_str(), pixelRatio); -#endif -} void CScreenSaver::Start() { // notify screen saver that they should start - m_pScr->Start(); + if (Initialized()) m_pStruct->Start(); } void CScreenSaver::Render() { // ask screensaver to render itself - m_pScr->Render(); + if (Initialized()) m_pStruct->Render(); } void CScreenSaver::Stop() { // ask screensaver to cleanup - m_pScr->Stop(); + if (Initialized()) m_pStruct->Stop(); } void CScreenSaver::GetInfo(SCR_INFO *info) { // get info from screensaver - m_pScr->GetInfo(info); + if (Initialized()) m_pStruct->GetInfo(info); } diff --git a/xbmc/screensavers/ScreenSaver.h b/xbmc/screensavers/ScreenSaver.h index 615a1a8b17..e0b939395c 100644 --- a/xbmc/screensavers/ScreenSaver.h +++ b/xbmc/screensavers/ScreenSaver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2009 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -18,46 +18,21 @@ * http://www.gnu.org/copyleft/gpl.html * */ -// Screensaver.h: interface for the CScreensaver class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_ScreenSaver_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_) -#define AFX_ScreenSaver_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_ - -#if _MSC_VER > 1000 #pragma once -#endif // _MSC_VER > 1000 +#include "AddonDll.h" #include "DllScreenSaver.h" -#ifdef __cplusplus -extern "C" -{ -} -#endif - -#include <memory> - -class CScreenSaver +class CScreenSaver : public ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS> { public: - CScreenSaver(struct ScreenSaver* pScr, DllScreensaver* pDll, const CStdString& strScreenSaverName); - ~CScreenSaver(); + CScreenSaver(const ADDON::AddonProps& props) : ADDON::CAddonDll<DllScreenSaver, ScreenSaver, SCR_PROPS>(props) {}; + virtual ~CScreenSaver() {} // Things that MUST be supplied by the child classes - void Create(); void Start(); void Render(); void Stop(); void GetInfo(SCR_INFO *info); - -protected: - std::auto_ptr<struct ScreenSaver> m_pScr; - std::auto_ptr<DllScreensaver> m_pDll; - CStdString m_strScreenSaverName; }; - -#endif // !defined(AFX_ScreenSaver_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_) - diff --git a/xbmc/screensavers/ScreenSaverFactory.cpp b/xbmc/screensavers/ScreenSaverFactory.cpp deleted file mode 100644 index b718c149ff..0000000000 --- a/xbmc/screensavers/ScreenSaverFactory.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ -#include "ScreenSaverFactory.h" -#include "Util.h" - - -CScreenSaverFactory::CScreenSaverFactory() -{} -CScreenSaverFactory::~CScreenSaverFactory() -{} - -extern "C" void __declspec(dllexport) get_module(struct ScreenSaver* pScr); - -CScreenSaver* CScreenSaverFactory::LoadScreenSaver(const CStdString& strScr) const -{ - // strip of the path & extension to get the name of the visualisation - CStdString strName = CUtil::GetFileName(strScr); - strName = strName.Left(strName.size() - 4); - - // load visualisation - DllScreensaver* pDll = new DllScreensaver; - pDll->SetFile(strScr); - pDll->EnableDelayedUnload(false); - if (!pDll->Load()) - { - delete pDll; - return NULL; - } - - struct ScreenSaver* pScr = (struct ScreenSaver*)malloc(sizeof(struct ScreenSaver)); - ZeroMemory(pScr, sizeof(struct ScreenSaver)); - pDll->GetModule(pScr); - - // and pass it to a new instance of CScreenSaver() which will handle the screensaver - return new CScreenSaver(pScr, pDll, strName); -} diff --git a/xbmc/screensavers/xbmc_scr.h b/xbmc/screensavers/xbmc_scr.h deleted file mode 100644 index 19aae64a74..0000000000 --- a/xbmc/screensavers/xbmc_scr.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __XBMC_SCR_H__
-#define __XBMC_SCR_H__
-
-#ifndef _LINUX
-#include <xtl.h>
-#else
-#define __cdecl -#define __declspec(x) -#endif
- -extern "C" -{ - -struct SCR_INFO -{ - int dummy; -}; - - // Functions that your visualisation must implement
-#ifndef _LINUX
- void Create(LPDIRECT3DDEVICE8 pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float fPixelRatio);
-#else
- void Create(void* pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float fPixelRatio);
-#endif
- void Start(); - void Render(); - void Stop(); - void GetInfo(SCR_INFO* pInfo) - { - } - -
- // Structure to transfer the above functions to XBMC
- struct ScreenSaver
- {
-#ifndef _LINUX - void (__cdecl* Create)(LPDIRECT3DDEVICE8 pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float pixelRatio); -#else - void (__cdecl* Create)(void* pd3dDevice, int iWidth, int iHeight, const char* szScreensaver, float pixelRatio); -#endif - void (__cdecl* Start) (); - void (__cdecl* Render) (); - void (__cdecl* Stop) (); - void (__cdecl* GetInfo)(SCR_INFO *info); - };
-
- // function to export the above structure to XBMC
- void __declspec(dllexport) get_module(struct ScreenSaver* pScr)
- {
- pScr->Create = Create;
- pScr->Start = Start;
- pScr->Render = Render;
- pScr->Stop = Stop;
- pScr->GetInfo = GetInfo;
- };
-};
-
-#endif
diff --git a/xbmc/utils/Addon.cpp b/xbmc/utils/Addon.cpp new file mode 100644 index 0000000000..e71215208a --- /dev/null +++ b/xbmc/utils/Addon.cpp @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "Addon.h" +#include "AddonManager.h" +#include "Settings.h" +#include "GUISettings.h" +#include "StringUtils.h" +#include "FileSystem/Directory.h" +#include "log.h" +#include <string.h> + +using XFILE::CDirectory; + +namespace ADDON +{ + +/** + * helper functions + * + */ + +const CStdString TranslateContent(const CONTENT_TYPE &type, bool pretty/*=false*/) +{ + switch (type) + { + case CONTENT_ALBUMS: + { + if (pretty) + return g_localizeStrings.Get(132); + return "albums"; + } + case CONTENT_ARTISTS: + { + if (pretty) + return g_localizeStrings.Get(133); + return "artists"; + } + case CONTENT_MOVIES: + { + if (pretty) + return g_localizeStrings.Get(20342); + return "movies"; + } + case CONTENT_TVSHOWS: + { + if (pretty) + return g_localizeStrings.Get(20343); + return "tvshows"; + } + case CONTENT_MUSICVIDEOS: + { + if (pretty) + return g_localizeStrings.Get(20389); + return "musicvideos"; + } + case CONTENT_EPISODES: + { + if (pretty) + return g_localizeStrings.Get(20360); + return "episodes"; + } + case CONTENT_PROGRAMS: + { + return "programs"; + } + case CONTENT_NONE: + { + if (pretty) + return g_localizeStrings.Get(231); + return ""; + } + default: + { + return ""; + } + } +} + +const CONTENT_TYPE TranslateContent(const CStdString &string) +{ + if (string.Equals("albums")) return CONTENT_ALBUMS; + else if (string.Equals("artists")) return CONTENT_ARTISTS; + else if (string.Equals("movies")) return CONTENT_MOVIES; + else if (string.Equals("tvshows")) return CONTENT_TVSHOWS; + else if (string.Equals("episodes")) return CONTENT_EPISODES; + else if (string.Equals("musicvideos")) return CONTENT_MUSICVIDEOS; + else if (string.Equals("plugin")) return CONTENT_PLUGIN; + else if (string.Equals("programs")) return CONTENT_PROGRAMS; + else return CONTENT_NONE; +} + +const CStdString TranslateType(const ADDON::TYPE &type, bool pretty/*=false*/) +{ + switch (type) + { + case ADDON::ADDON_SCRAPER: + { + if (pretty) + return g_localizeStrings.Get(24007); + return "scraper"; + } + case ADDON::ADDON_SCRAPER_LIBRARY: + { + return "scraper-library"; + } + case ADDON::ADDON_SCREENSAVER: + { + if (pretty) + return g_localizeStrings.Get(24008); + return "screensaver"; + } + case ADDON::ADDON_VIZ: + { + if (pretty) + return g_localizeStrings.Get(24010); + return "visualization"; + } + case ADDON::ADDON_VIZ_LIBRARY: + { + return "visualization-library"; + } + case ADDON::ADDON_PLUGIN: + { + if (pretty) + return g_localizeStrings.Get(24005); + return "plugin"; + } + case ADDON::ADDON_SCRIPT: + { + if (pretty) + return g_localizeStrings.Get(24009); + return "script"; + } + default: + { + return ""; + } + } +} + +const ADDON::TYPE TranslateType(const CStdString &string) +{ + if (string.Equals("pvrclient")) return ADDON_PVRDLL; + else if (string.Equals("scraper")) return ADDON_SCRAPER; + else if (string.Equals("scraper-library")) return ADDON_SCRAPER_LIBRARY; + else if (string.Equals("screensaver")) return ADDON_SCREENSAVER; + else if (string.Equals("visualization")) return ADDON_VIZ; + else if (string.Equals("visualization-library")) return ADDON_VIZ_LIBRARY; + else if (string.Equals("plugin")) return ADDON_PLUGIN; + else if (string.Equals("script")) return ADDON_SCRIPT; + else return ADDON_UNKNOWN; +} + +/** + * AddonVersion + * + */ + +bool AddonVersion::operator==(const AddonVersion &rhs) const +{ + return str.Equals(rhs.str); +} + +bool AddonVersion::operator!=(const AddonVersion &rhs) const +{ + return !(*this == rhs); +} + +bool AddonVersion::operator>(const AddonVersion &rhs) const +{ + return (strverscmp(str.c_str(), rhs.str.c_str()) > 0); +} + +bool AddonVersion::operator>=(const AddonVersion &rhs) const +{ + return (*this == rhs) || (*this > rhs); +} + +bool AddonVersion::operator<(const AddonVersion &rhs) const +{ + return (strverscmp(str.c_str(), rhs.str.c_str()) < 0); +} + +bool AddonVersion::operator<=(const AddonVersion &rhs) const +{ + return (*this == rhs) || !(*this > rhs); +} + +CStdString AddonVersion::Print() const +{ + CStdString out; + out.Format("%s %s", g_localizeStrings.Get(24051), str); // "Version: <str>" + return CStdString(out); +} + +/** + * CAddon + * + */ + +CAddon::CAddon(const AddonProps &props) + : m_props(props) + , m_parent(AddonPtr()) +{ + if (props.libname.empty()) BuildLibName(); + else m_strLibName = props.libname; + m_strProfile = GetProfilePath(); + m_userSettingsPath = GetUserSettingsPath(); + m_disabled = true; +} + +CAddon::CAddon(const CAddon &rhs, const AddonPtr &parent) + : m_props(rhs.Props()) + , m_parent(parent) +{ + m_props.uuid = StringUtils::CreateUUID(); + m_userXmlDoc = rhs.m_userXmlDoc; + m_strProfile = GetProfilePath(); + m_userSettingsPath = GetUserSettingsPath(); + m_strLibName = rhs.LibName(); + m_disabled = false; +} + +AddonPtr CAddon::Clone(const AddonPtr &self) const +{ + return AddonPtr(new CAddon(*this, self)); +} + +const AddonVersion CAddon::Version() +{ + return m_props.version; +} + +//TODO platform/path crap should be negotiated between the addon and +// the handler for it's type +void CAddon::BuildLibName() +{ + m_strLibName = "default"; + CStdString ext; + switch (m_props.type) + { + case ADDON_SCRAPER: + case ADDON_SCRAPER_LIBRARY: + ext = ADDON_SCRAPER_EXT; + break; + case ADDON_SCREENSAVER: + ext = ADDON_SCREENSAVER_EXT; + break; + case ADDON_VIZ: + ext = ADDON_VIS_EXT; + break; + case ADDON_PLUGIN: + ext = ADDON_PYTHON_EXT; + break; + default: + m_strLibName.clear(); + return; + } + // extensions are returned as *.ext + // so remove the asterisk + ext.erase(0,1); + m_strLibName.append(ext); +} + +/** + * Language File Handling + */ +bool CAddon::LoadStrings() +{ + if (!HasSettings()) + return false; + + // Path where the language strings reside + CStdString pathToLanguageFile = m_props.path; + CStdString pathToFallbackLanguageFile = m_props.path; + CUtil::AddFileToFolder(pathToLanguageFile, "resources", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "resources", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, "language", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "language", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, g_guiSettings.GetString("locale.language"), pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "english", pathToFallbackLanguageFile); + CUtil::AddFileToFolder(pathToLanguageFile, "strings.xml", pathToLanguageFile); + CUtil::AddFileToFolder(pathToFallbackLanguageFile, "strings.xml", pathToFallbackLanguageFile); + + // Load language strings temporarily + return m_strings.Load(pathToLanguageFile, pathToFallbackLanguageFile); +} + +void CAddon::ClearStrings() +{ + // Unload temporary language strings + m_strings.Clear(); +} + +CStdString CAddon::GetString(uint32_t id) const +{ + return m_strings.Get(id); +} + +/** + * Settings Handling + */ +bool CAddon::HasSettings() +{ + CStdString addonFileName = m_props.path; + CUtil::AddFileToFolder(addonFileName, "resources", addonFileName); + CUtil::AddFileToFolder(addonFileName, "settings.xml", addonFileName); + + // Load the settings file to verify it's valid + TiXmlDocument xmlDoc; + if (!xmlDoc.LoadFile(addonFileName)) + return false; + + // Make sure that the addon XML has the settings element + TiXmlElement *setting = xmlDoc.RootElement(); + if (!setting || strcmpi(setting->Value(), "settings") != 0) + return false; + + return true; +} + +bool CAddon::LoadSettings() +{ + CStdString addonFileName = m_props.path; + CUtil::AddFileToFolder(addonFileName, "resources", addonFileName); + CUtil::AddFileToFolder(addonFileName, "settings.xml", addonFileName); + + if (!m_addonXmlDoc.LoadFile(addonFileName)) + { + CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", addonFileName.c_str(), m_addonXmlDoc.ErrorRow(), m_addonXmlDoc.ErrorDesc()); + return false; + } + + // Make sure that the addon XML has the settings element + TiXmlElement *setting = m_addonXmlDoc.RootElement(); + if (!setting || strcmpi(setting->Value(), "settings") != 0) + { + CLog::Log(LOGERROR, "Error loading Settings %s: cannot find root element 'settings'", addonFileName.c_str()); + return false; + } + return LoadUserSettings(); +} + +bool CAddon::LoadUserSettings() +{ + // Load the user saved settings. If it does not exist, create it + if (!m_userXmlDoc.LoadFile(m_userSettingsPath)) + { + TiXmlDocument doc; + TiXmlDeclaration decl("1.0", "UTF-8", "yes"); + doc.InsertEndChild(decl); + + TiXmlElement xmlRootElement("settings"); + doc.InsertEndChild(xmlRootElement); + + m_userXmlDoc = doc; + } + return true; +} + +void CAddon::SaveSettings(void) +{ + // break down the path into directories + CStdString strRoot, strAddon; + CUtil::GetDirectory(m_userSettingsPath, strAddon); + CUtil::RemoveSlashAtEnd(strAddon); + CUtil::GetDirectory(strAddon, strRoot); + CUtil::RemoveSlashAtEnd(strRoot); + + // create the individual folders + if (!CDirectory::Exists(strRoot)) + CDirectory::Create(strRoot); + if (!CDirectory::Exists(strAddon)) + CDirectory::Create(strAddon); + + m_userXmlDoc.SaveFile(m_userSettingsPath); +} + +void CAddon::SaveFromDefault() +{ + if (!GetSettingsXML()) + { // no settings found + return; + } + + const TiXmlElement *setting = GetSettingsXML()->FirstChildElement("setting"); + while (setting) + { + CStdString id; + if (setting->Attribute("id")) + id = setting->Attribute("id"); + CStdString type; + if (setting->Attribute("type")) + type = setting->Attribute("type"); + CStdString value; + if (setting->Attribute("default")) + value = setting->Attribute("default"); + UpdateSetting(id, type, value); + setting = setting->NextSiblingElement("setting"); + } + + // now save to file + SaveSettings(); +} + +CStdString CAddon::GetSetting(const CStdString& key) const +{ + if (m_userXmlDoc.RootElement()) + { + // Try to find the setting and return its value + const TiXmlElement *setting = m_userXmlDoc.RootElement()->FirstChildElement("setting"); + while (setting) + { + const char *id = setting->Attribute("id"); + if (id && strcmpi(id, key) == 0) + return setting->Attribute("value"); + + setting = setting->NextSiblingElement("setting"); + } + } + + if (m_addonXmlDoc.RootElement()) + { + // Try to find the setting in the addon and return its default value + const TiXmlElement* setting = m_addonXmlDoc.RootElement()->FirstChildElement("setting"); + while (setting) + { + const char *id = setting->Attribute("id"); + if (id && strcmpi(id, key) == 0 && setting->Attribute("default")) + return setting->Attribute("default"); + + setting = setting->NextSiblingElement("setting"); + } + } + + // Otherwise return empty string + return ""; +} + +void CAddon::UpdateSetting(const CStdString& key, const CStdString& value, const CStdString& type/* = "" */) +{ + if (key.empty()) return; + + // Try to find the setting and change its value + if (!m_userXmlDoc.RootElement()) + { + TiXmlElement node("settings"); + m_userXmlDoc.InsertEndChild(node); + } + TiXmlElement *setting = m_userXmlDoc.RootElement()->FirstChildElement("setting"); + while (setting) + { + const char *id = setting->Attribute("id"); + const char *storedtype = setting->Attribute("type"); + if (id && strcmpi(id, key) == 0) + { + if (!type.empty() && storedtype && strcmpi(storedtype, type) != 0) + setting->SetAttribute("type", type.c_str()); + + setting->SetAttribute("value", value.c_str()); + return; + } + setting = setting->NextSiblingElement("setting"); + } + + // Setting not found, add it + TiXmlElement nodeSetting("setting"); + nodeSetting.SetAttribute("id", std::string(key.c_str())); //FIXME otherwise attribute value isn't updated + if (!type.empty()) + nodeSetting.SetAttribute("type", std::string(type.c_str())); + else + nodeSetting.SetAttribute("type", "text"); + nodeSetting.SetAttribute("value", std::string(value.c_str())); + m_userXmlDoc.RootElement()->InsertEndChild(nodeSetting); +} + +TiXmlElement* CAddon::GetSettingsXML() +{ + return m_addonXmlDoc.RootElement(); +} + +CStdString CAddon::GetProfilePath() +{ + CStdString profile; + profile.Format("special://profile/addon_data/%s/", UUID().c_str()); + return profile; +} + +CStdString CAddon::GetUserSettingsPath() +{ + CStdString path; + CUtil::AddFileToFolder(Profile(), "settings.xml", path); + return path; +} + +/** + * CAddonLibrary + * + */ + +CAddonLibrary::CAddonLibrary(const AddonProps& props) + : CAddon(props) + , m_addonType(SetAddonType()) +{ +} + +TYPE CAddonLibrary::SetAddonType() +{ + if (Type() == ADDON_SCRAPER_LIBRARY) + return ADDON_SCRAPER; + else if (Type() == ADDON_VIZ_LIBRARY) + return ADDON_VIZ; + else + return ADDON_UNKNOWN; +} + +} /* namespace ADDON */ + diff --git a/xbmc/utils/Addon.h b/xbmc/utils/Addon.h new file mode 100644 index 0000000000..b599f6dae2 --- /dev/null +++ b/xbmc/utils/Addon.h @@ -0,0 +1,176 @@ +#pragma once +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "IAddon.h" +#include "tinyXML/tinyxml.h" +#include "Util.h" +#include "URL.h" +#include "LocalizeStrings.h" +#include <ostream> + +class CURL; +class TiXmlElement; + +namespace ADDON +{ + +// utils +const CStdString TranslateContent(const CONTENT_TYPE &content, bool pretty=false); +const CONTENT_TYPE TranslateContent(const CStdString &string); +const CStdString TranslateType(const TYPE &type, bool pretty=false); +const TYPE TranslateType(const CStdString &string); + +struct AddonVersion +{ +public: + AddonVersion(const CStdString &str) : str(str) {} + bool operator==(const AddonVersion &rhs) const; + bool operator!=(const AddonVersion &rhs) const; + bool operator>(const AddonVersion &rhs) const; + bool operator>=(const AddonVersion &rhs) const; + bool operator<(const AddonVersion &rhs) const; + bool operator<=(const AddonVersion &rhs) const; + CStdString Print() const; + const CStdString str; +}; + +struct AddonProps +{ +public: + AddonProps(CStdString &uuid, TYPE type, CStdString &versionstr) + : uuid(uuid) + , type(type) + , version(versionstr) + {} + + AddonProps(const AddonPtr &addon) + : uuid(addon->UUID()) + , type(addon->Type()) + , version(addon->Version()) + { if(addon->Parent()) parent = addon->Parent()->UUID(); } + + bool operator=(const AddonProps &rhs) + { return (*this).uuid == rhs.uuid + && (*this).type == rhs.type + && (*this).version == rhs.version; } + CStdString uuid; + TYPE type; + AddonVersion version; + CStdString name; + CStdString parent; + CStdString license; + CStdString summary; + CStdString description; + CStdString path; + CStdString libname; + CStdString author; + CStdString source; + CStdString icon; + CStdString disclaimer; + std::set<CONTENT_TYPE> contents; + int stars; +}; +typedef std::vector<struct AddonProps> VECADDONPROPS; + +class CAddon : public IAddon +{ +public: + CAddon(const AddonProps &addonprops); + virtual ~CAddon() {} + virtual AddonPtr Clone(const AddonPtr& parent) const; + + // settings & language + virtual bool HasSettings(); + virtual bool LoadSettings(); + virtual void SaveSettings(); + virtual void SaveFromDefault(); + virtual void UpdateSetting(const CStdString& key, const CStdString& value, const CStdString &type = ""); + virtual CStdString GetSetting(const CStdString& key) const; + TiXmlElement* GetSettingsXML(); + virtual CStdString GetString(uint32_t id) const; + + // properties + const TYPE Type() const { return m_props.type; } + AddonProps Props() const { return m_props; } + const CStdString UUID() const { return m_props.uuid; } + const AddonPtr Parent() const { return m_parent; } + const CStdString Name() const { return m_props.name; } + bool Disabled() const { return m_disabled; } + const AddonVersion Version(); + const CStdString Summary() const { return m_props.summary; } + const CStdString Description() const { return m_props.description; } + const CStdString Path() const { return m_props.path; } + const CStdString Profile() const { return m_strProfile; } + const CStdString LibName() const { return m_props.libname; } + const CStdString Author() const { return m_props.author; } + const CStdString Icon() const { return m_props.icon; } + const int Stars() const { return m_props.stars; } + const CStdString Disclaimer() const { return m_props.disclaimer; } + bool Supports(const CONTENT_TYPE &content) const { return (m_props.contents.count(content) == 1); } + ADDONDEPS GetDeps() { return m_dependencies; } + +protected: + CAddon(const CAddon&); // protected as all copying is handled by Clone() + CAddon(const CAddon&, const AddonPtr&); + bool LoadUserSettings(); + TiXmlDocument m_addonXmlDoc; + TiXmlDocument m_userXmlDoc; + CStdString m_userSettingsPath; + +private: + friend class AddonMgr; + AddonProps m_props; + const AddonPtr m_parent; + CStdString GetProfilePath(); + CStdString GetUserSettingsPath(); + + virtual bool IsAddonLibrary() { return false; } + + void Enable() { LoadStrings(); m_disabled = false; } + void Disable() { m_disabled = true; ClearStrings();} + + virtual bool LoadStrings(); + virtual void ClearStrings(); + + void SetDeps(ADDONDEPS& deps) { m_dependencies = deps; } + ADDONDEPS m_dependencies; + + void BuildLibName(); + CStdString m_strProfile; + CStdString m_strLibName; + bool m_disabled; + CLocalizeStrings m_strings; +}; + +class CAddonLibrary : public CAddon +{ +public: + CAddonLibrary(const AddonProps &props); + +private: + virtual bool IsAddonLibrary() { return true; } + TYPE SetAddonType(); + const TYPE m_addonType; // addon type this library enhances +}; + +}; /* namespace ADDON */ + diff --git a/xbmc/utils/AddonDll.h b/xbmc/utils/AddonDll.h new file mode 100644 index 0000000000..69c9197c24 --- /dev/null +++ b/xbmc/utils/AddonDll.h @@ -0,0 +1,399 @@ +#pragma once +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ +#include "Addon.h" +#include "../DllAddon.h" +#include "AddonManager.h" +#include "GUIDialogSettings.h" +#include "Util.h" +#include "FileSystem/File.h" +#include "FileSystem/SpecialProtocol.h" +#include "FileSystem/Directory.h" +#include "log.h" + +using namespace XFILE; + +namespace ADDON +{ + template<class TheDll, typename TheStruct, typename TheProps> + class CAddonDll : public CAddon + { + public: + CAddonDll(const AddonProps &props); + virtual ~CAddonDll(); + AddonPtr Clone() const; + virtual ADDON_STATUS GetStatus(); + virtual void Remove(); + + // addon settings + virtual bool HasSettings(); + virtual bool LoadSettings(); + virtual void SaveSettings(); + virtual void SaveFromDefault(); + virtual CStdString GetSetting(const CStdString& key); + + bool Create(); + void Destroy(); + + protected: + bool LoadDll(); + void HandleException(std::exception &e, const char* context); + bool Initialized() { return m_initialized; } + TheStruct* m_pStruct; + TheProps* m_pInfo; + + private: + TheDll* m_pDll; + bool m_initialized; + + virtual ADDON_STATUS TransferSettings(); + TiXmlElement MakeSetting(DllSetting& setting) const; + + static void AddOnStatusCallback(void *userData, const ADDON_STATUS status, const char* msg); + static bool AddOnGetSetting(void *userData, const char *settingName, void *settingValue); + static void AddOnOpenSettings(const char *url, bool bReload); + static void AddOnOpenOwnSettings(void *userData, bool bReload); + static const char* AddOnGetAddonDirectory(void *userData); + static const char* AddOnGetUserDirectory(void *userData); + }; + +template<class TheDll, typename TheStruct, typename TheProps> +CAddonDll<TheDll, TheStruct, TheProps>::CAddonDll(const AddonProps &props) + : CAddon(props) +{ + m_pStruct = NULL; + m_initialized = false; + m_pDll = NULL; + m_pInfo = NULL; +} + +template<class TheDll, typename TheStruct, typename TheProps> +CAddonDll<TheDll, TheStruct, TheProps>::~CAddonDll() +{ + if (m_initialized) + Destroy(); +} + +template<class TheDll, typename TheStruct, typename TheProps> +AddonPtr CAddonDll<TheDll, TheStruct, TheProps>::Clone() const +{ + return AddonPtr(new CAddonDll<TheDll, TheStruct, TheProps>(*this)); +} + +template<class TheDll, typename TheStruct, typename TheProps> +bool CAddonDll<TheDll, TheStruct, TheProps>::LoadDll() +{ + CStdString strFileName; + if (!Parent()) + { + strFileName = Path() + LibName(); + } + else + { //FIXME hack to load same Dll twice + CStdString extension = CUtil::GetExtension(LibName()); + strFileName = "special://temp/" + LibName(); + CUtil::RemoveExtension(strFileName); + strFileName += "-" + UUID() + extension; + + if (!CFile::Exists(strFileName)) + CFile::Cache(Path() + LibName(), strFileName); + + CLog::Log(LOGNOTICE, "ADDON: Loaded virtual child addon %s", strFileName.c_str()); + } + + /* Load the Dll */ + m_pDll = new TheDll; + m_pDll->SetFile(strFileName); + m_pDll->EnableDelayedUnload(false); + if (!m_pDll->Load()) + { + delete m_pDll; + m_pDll = NULL; + new CAddonStatusHandler(this, STATUS_UNKNOWN, "Can't load Dll", false); + return false; + } + m_pStruct = (TheStruct*)malloc(sizeof(TheStruct)); + ZeroMemory(m_pStruct, sizeof(TheStruct)); + m_pDll->GetAddon(m_pStruct); + return (m_pStruct != NULL); +} + +template<class TheDll, typename TheStruct, typename TheProps> +bool CAddonDll<TheDll, TheStruct, TheProps>::Create() +{ + CLog::Log(LOGDEBUG, "ADDON: Dll Initializing - %s", Name().c_str()); + m_initialized = false; + + if (!LoadDll()) + return false; + + try + { + ADDON_STATUS status = m_pDll->Create(NULL, m_pInfo); + if (status != STATUS_OK) + throw status; + m_initialized = true; + } + catch (std::exception &e) + { + HandleException(e, "m_pDll->Create"); + } + catch (ADDON_STATUS status) + { + if (status == STATUS_NEED_SETTINGS) + { // catch request for settings in initalization + if (TransferSettings() == STATUS_OK) + m_initialized = true; + else + new CAddonStatusHandler(this, status, "", false); + } + else + { // Addon failed initialization + CLog::Log(LOGERROR, "ADDON: Dll %s - Client returned bad status (%i) from Create and is not usable", Name().c_str(), status); + new CAddonStatusHandler(this, status, "", false); + } + } + + return m_initialized; +} + +template<class TheDll, typename TheStruct, typename TheProps> +void CAddonDll<TheDll, TheStruct, TheProps>::Destroy() +{ + delete m_pStruct; + m_pStruct = NULL; + delete m_pDll; + m_pDll = NULL; + m_initialized = false; + CLog::Log(LOGINFO, "ADDON: Dll Destroyed - %s", Name().c_str()); +} + +template<class TheDll, typename TheStruct, typename TheProps> +void CAddonDll<TheDll, TheStruct, TheProps>::Remove() +{ + /* Unload library file */ + try + { + m_pDll->Unload(); + } + catch (std::exception &e) + { + HandleException(e, "m_pDll->Unload"); + } +} + +template<class TheDll, typename TheStruct, typename TheProps> +ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::GetStatus() +{ + try + { + return m_pDll->GetStatus(); + } + catch (std::exception &e) + { + HandleException(e, "m_pDll->GetStatus()"); + } + return STATUS_UNKNOWN; +} + +template<class TheDll, typename TheStruct, typename TheProps> +bool CAddonDll<TheDll, TheStruct, TheProps>::HasSettings() +{ + if (!LoadDll()) + return false; + + try + { + return m_pDll->HasSettings(); + } + catch (std::exception &e) + { + HandleException(e, "m_pDll->HasSettings()"); + return false; + } +} + +template<class TheDll, typename TheStruct, typename TheProps> +bool CAddonDll<TheDll, TheStruct, TheProps>::LoadSettings() +{ + if (!LoadDll()) + return false; + + StructSetting** sSet; + std::vector<DllSetting> vSet; + unsigned entries = 0; + try + { + entries = m_pDll->GetSettings(&sSet); + DllUtils::StructToVec(entries, &sSet, &vSet); + m_pDll->FreeSettings(); + } + catch (std::exception &e) + { + HandleException(e, "m_pDll->GetSettings()"); + return false; + } + + if (vSet.size()) + { + // regenerate XML doc + m_addonXmlDoc.Clear(); + TiXmlElement node("settings"); + m_addonXmlDoc.InsertEndChild(node); + + for (unsigned i=0; i < entries; i++) + { + DllSetting& setting = vSet[i]; + m_addonXmlDoc.RootElement()->InsertEndChild(MakeSetting(setting)); + } + } + else + return CAddon::LoadSettings(); + + return CAddon::LoadUserSettings(); +} + +template<class TheDll, typename TheStruct, typename TheProps> +TiXmlElement CAddonDll<TheDll, TheStruct, TheProps>::MakeSetting(DllSetting& setting) const +{ + TiXmlElement node("setting"); + + switch (setting.type) + { + case DllSetting::CHECK: + { + node.SetAttribute("id", setting.id); + node.SetAttribute("type", "bool"); + node.SetAttribute("label", setting.label); + break; + } + case DllSetting::SPIN: + { + node.SetAttribute("id", setting.id); + node.SetAttribute("type", "enum"); + node.SetAttribute("label", setting.label); + CStdString values; + for (unsigned int i = 0; i < setting.entry.size(); i++) + { + values.append(setting.entry[i]); + values.append("|"); + } + node.SetAttribute("values", values.c_str()); + break; + } + default: + break; + } + + return node; +} + +template<class TheDll, typename TheStruct, typename TheProps> +void CAddonDll<TheDll, TheStruct, TheProps>::SaveSettings() +{ + // must save first, as TransferSettings() reloads saved settings! + CAddon::SaveSettings(); + TransferSettings(); +} + +template<class TheDll, typename TheStruct, typename TheProps> +void CAddonDll<TheDll, TheStruct, TheProps>::SaveFromDefault() +{ + CAddon::SaveFromDefault(); + TransferSettings(); +} + +template<class TheDll, typename TheStruct, typename TheProps> +CStdString CAddonDll<TheDll, TheStruct, TheProps>::GetSetting(const CStdString& key) +{ + return CAddon::GetSetting(key); +} + +template<class TheDll, typename TheStruct, typename TheProps> +ADDON_STATUS CAddonDll<TheDll, TheStruct, TheProps>::TransferSettings() +{ + bool restart = false; + ADDON_STATUS reportStatus = STATUS_OK; + + CLog::Log(LOGDEBUG, "Calling TransferSettings for: %s", Name().c_str()); + + LoadUserSettings(); + + TiXmlElement *setting = m_userXmlDoc.RootElement()->FirstChildElement("setting"); + while (setting) + { + ADDON_STATUS status = STATUS_OK; + const char *id = setting->Attribute("id"); + const char *type = setting->Attribute("type"); + + if (type) + { + if (strcmpi(type, "text") == 0 || strcmpi(type, "ipaddress") == 0 || + strcmpi(type, "folder") == 0 || strcmpi(type, "action") == 0 || + strcmpi(type, "music") == 0 || strcmpi(type, "pictures") == 0 || + strcmpi(type, "folder") == 0 || strcmpi(type, "programs") == 0 || + strcmpi(type, "files") == 0 || strcmpi(type, "fileenum") == 0) + { + status = m_pDll->SetSetting(id, (const char*) GetSetting(id).c_str()); + } + else if (strcmpi(type, "integer") == 0 || strcmpi(type, "enum") == 0 || + strcmpi(type, "labelenum") == 0) + { + int tmp = atoi(GetSetting(id)); + status = m_pDll->SetSetting(id, (int*) &tmp); + } + else if (strcmpi(type, "bool") == 0) + { + bool tmp = (GetSetting(id) == "true") ? true : false; + status = m_pDll->SetSetting(id, (bool*) &tmp); + } + else + { + CLog::Log(LOGERROR, "Unknown setting type '%s' for %s", type, Name().c_str()); + } + + if (status == STATUS_NEED_RESTART) + restart = true; + else if (status != STATUS_OK) + reportStatus = status; + } + setting = setting->NextSiblingElement("setting"); + } + + if (restart || reportStatus != STATUS_OK) + { + //FIXME + //new CAddonStatusHandler(this, restart ? STATUS_NEED_RESTART : reportStatus, "", true); + } + + return STATUS_OK; +} + +template<class TheDll, typename TheStruct, typename TheProps> +void CAddonDll<TheDll, TheStruct, TheProps>::HandleException(std::exception &e, const char* context) +{ + m_initialized = false; + m_pDll->Unload(); + CLog::Log(LOGERROR, "ADDON: Dll %s, throws an exception '%s' during %s. Contact developer '%s' with bug reports", Name().c_str(), e.what(), context, Author().c_str()); +} + +}; /* namespace ADDON */ + diff --git a/xbmc/utils/AddonManager.cpp b/xbmc/utils/AddonManager.cpp new file mode 100644 index 0000000000..0af7c9e6b0 --- /dev/null +++ b/xbmc/utils/AddonManager.cpp @@ -0,0 +1,1198 @@ +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ +#include "AddonManager.h" +#include "Addon.h" +#include "Application.h" +#include "utils/log.h" +#include "StringUtils.h" +#include "RegExp.h" +#include "XMLUtils.h" +#include "GUIDialogYesNo.h" +#include "GUIDialogOK.h" +#include "GUIDialogAddonSettings.h" +#include "GUIWindowManager.h" +#include "FileItem.h" +#include "Settings.h" +#include "GUISettings.h" +#include "SingleLock.h" +#include "DownloadQueueManager.h" + +#ifdef HAS_VISUALISATION +#include "../visualizations/DllVisualisation.h" +#include "../visualizations/Visualisation.h" +#endif +#ifdef HAS_PVRCLIENTS +#include "../pvrclients/DllPVRClient.h" +#include "../pvrclients/PVRClient.h" +#endif +#ifdef HAS_SCREENSAVER +#include "../screensavers/DllScreenSaver.h" +#include "../screensavers/ScreenSaver.h" +#endif +//#ifdef HAS_SCRAPERS +#include "../Scraper.h" +//#endif + + +namespace ADDON +{ + +/********************************************************** + * CAddonStatusHandler - AddOn Status Report Class + * + * Used to informate the user about occurred errors and + * changes inside Add-on's, and ask him what to do. + * + */ + +CCriticalSection CAddonStatusHandler::m_critSection; + +CAddonStatusHandler::CAddonStatusHandler(IAddon* addon, ADDON_STATUS status, CStdString message, bool sameThread) + : m_addon(addon) +{ + if (m_addon == NULL) + return; + + CLog::Log(LOGINFO, "Called Add-on status handler for '%u' of clientName:%s, clientGUID:%s (same Thread=%s)", status, m_addon->Name().c_str(), m_addon->UUID().c_str(), sameThread ? "yes" : "no"); + + m_status = status; + m_message = message; + + if (sameThread) + { + Process(); + } + else + { + CStdString ThreadName; + ThreadName.Format("Addon Status: %s", m_addon->Name().c_str()); + + Create(true, THREAD_MINSTACKSIZE); + SetName(ThreadName.c_str()); + SetPriority(-15); + } +} + +CAddonStatusHandler::~CAddonStatusHandler() +{ + StopThread(); +} + +void CAddonStatusHandler::OnStartup() +{ +} + +void CAddonStatusHandler::OnExit() +{ +} + +void CAddonStatusHandler::Process() +{ + CSingleLock lock(m_critSection); + + CStdString heading; + heading.Format("%s: %s", TranslateType(m_addon->Type(), true).c_str(), m_addon->Name().c_str()); + + /* AddOn lost connection to his backend (for ones that use Network) */ + if (m_status == STATUS_LOST_CONNECTION) + { + CGUIDialogYesNo* pDialog = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO); + if (!pDialog) return; + + pDialog->SetHeading(heading); + pDialog->SetLine(1, 24070); + pDialog->SetLine(2, 24073); + + //send message and wait for user input + ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()}; + g_application.getApplicationMessenger().SendMessage(tMsg, true); + + if (pDialog->IsConfirmed()) + CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, false); + } + /* Request to restart the AddOn and data structures need updated */ + else if (m_status == STATUS_NEED_RESTART) + { + CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK); + if (!pDialog) return; + + pDialog->SetHeading(heading); + pDialog->SetLine(1, 24074); + + //send message and wait for user input + ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()}; + g_application.getApplicationMessenger().SendMessage(tMsg, true); + + CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true); + } + /* Some required settings are missing/invalid */ + else if (m_status == STATUS_NEED_SETTINGS) + { + CGUIDialogYesNo* pDialogYesNo = (CGUIDialogYesNo*)g_windowManager.GetWindow(WINDOW_DIALOG_YES_NO); + if (!pDialogYesNo) return; + + pDialogYesNo->SetHeading(heading); + pDialogYesNo->SetLine(1, 24070); + pDialogYesNo->SetLine(2, 24072); + pDialogYesNo->SetLine(3, m_message); + + //send message and wait for user input + ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_YES_NO, g_windowManager.GetActiveWindow()}; + g_application.getApplicationMessenger().SendMessage(tMsg, true); + + if (!pDialogYesNo->IsConfirmed()) return; + + if (!m_addon->HasSettings()) + return; + + const AddonPtr addon(m_addon); + if (CGUIDialogAddonSettings::ShowAndGetInput(addon)) + { + //todo doesn't dialogaddonsettings save these automatically? should do + m_addon->SaveSettings(); + CAddonMgr::Get()->GetCallbackForType(m_addon->Type())->RequestRestart(m_addon, true); + } + else + m_addon->LoadSettings(); + } + /* A unknown event has occurred */ + else if (m_status == STATUS_UNKNOWN) + { + CGUIDialogOK* pDialog = (CGUIDialogOK*)g_windowManager.GetWindow(WINDOW_DIALOG_OK); + if (!pDialog) return; + + pDialog->SetHeading(heading); + pDialog->SetLine(1, 24070); + pDialog->SetLine(2, 24071); + pDialog->SetLine(3, m_message); + + //send message and wait for user input + ThreadMessage tMsg = {TMSG_DIALOG_DOMODAL, WINDOW_DIALOG_OK, g_windowManager.GetActiveWindow()}; + g_application.getApplicationMessenger().SendMessage(tMsg, true); + } +} + + +/********************************************************** + * CAddonMgr + * + */ + +CAddonMgr* CAddonMgr::m_pInstance = NULL; +std::map<TYPE, IAddonMgrCallback*> CAddonMgr::m_managers; + +CAddonMgr::CAddonMgr() +{ +} + +CAddonMgr::~CAddonMgr() +{ +} + +CAddonMgr* CAddonMgr::Get() +{ + if (!m_pInstance) + { + m_pInstance = new CAddonMgr(); + } + return m_pInstance; +} + +IAddonMgrCallback* CAddonMgr::GetCallbackForType(TYPE type) +{ + if (m_managers.find(type) == m_managers.end()) + return NULL; + else + return m_managers[type]; +} + +bool CAddonMgr::RegisterAddonMgrCallback(const TYPE type, IAddonMgrCallback* cb) +{ + if (cb == NULL) + return false; + + m_managers.erase(type); + m_managers[type] = cb; + + return true; +} + +void CAddonMgr::UnregisterAddonMgrCallback(TYPE type) +{ + m_managers.erase(type); +} + +bool CAddonMgr::HasAddons(const TYPE &type, const CONTENT_TYPE &content/*= CONTENT_NONE*/) +{ + if (content == CONTENT_NONE) + return (m_addons.find(type) != m_addons.end()); + + VECADDONS addons; + return GetAddons(type, addons, content, true); +} + +void CAddonMgr::UpdateRepos() +{ + m_downloads.push_back(g_DownloadManager.RequestFile(ADDON_XBMC_REPO_URL, this)); +} + +bool CAddonMgr::ParseRepoXML(const CStdString &path) +{ + //TODO + //check file exists, for each addoninfo, create an AddonProps struct, store in m_remoteAddons + return false; +} + +void CAddonMgr::OnFileComplete(TICKET aTicket, CStdString& aFilePath, INT aByteRxCount, Result aResult) +{ + for (unsigned i=0; i < m_downloads.size(); i++) + { + if (m_downloads[i].wQueueId == aTicket.wQueueId + && m_downloads[i].dwItemId == aTicket.dwItemId) + { + CLog::Log(LOGINFO, "ADDONS: Downloaded addons.xml"); + ParseRepoXML(aFilePath); + } + } +} + +bool CAddonMgr::GetAllAddons(VECADDONS &addons, bool enabledOnly/*= true*/) +{ + VECADDONS temp; + if (CAddonMgr::Get()->GetAddons(ADDON_PLUGIN, temp, CONTENT_NONE, enabledOnly)) + addons.insert(addons.end(), temp.begin(), temp.end()); + if (CAddonMgr::Get()->GetAddons(ADDON_SCRAPER, temp, CONTENT_NONE, enabledOnly)) + addons.insert(addons.end(), temp.begin(), temp.end()); + if (CAddonMgr::Get()->GetAddons(ADDON_SCREENSAVER, temp, CONTENT_NONE, enabledOnly)) + addons.insert(addons.end(), temp.begin(), temp.end()); + if (CAddonMgr::Get()->GetAddons(ADDON_SCRIPT, temp, CONTENT_NONE, enabledOnly)) + addons.insert(addons.end(), temp.begin(), temp.end()); + if (CAddonMgr::Get()->GetAddons(ADDON_VIZ, temp, CONTENT_NONE, enabledOnly)) + addons.insert(addons.end(), temp.begin(), temp.end()); + return !addons.empty(); +} + +bool CAddonMgr::GetAddons(const TYPE &type, VECADDONS &addons, const CONTENT_TYPE &content/*= CONTENT_NONE*/, bool enabledOnly/*= true*/) +{ + // recheck addons.xml & each addontype's directories no more than once every ADDON_DIRSCAN_FREQ seconds + CDateTimeSpan span; + span.SetDateTimeSpan(0, 0, 0, ADDON_DIRSCAN_FREQ); + if(!m_lastDirScan[type].IsValid() || (m_lastDirScan[type] + span) < CDateTime::GetCurrentDateTime()) + { + m_lastDirScan[type] = CDateTime::GetCurrentDateTime(); + LoadAddonsXML(type); + } + + addons.clear(); + if (m_addons.find(type) != m_addons.end()) + { + IVECADDONS itr = m_addons[type].begin(); + while (itr != m_addons[type].end()) + { // filter out what we're not looking for + if ((enabledOnly && (*itr)->Disabled()) + || (content != CONTENT_NONE && !(*itr)->Supports(content))) + { + ++itr; + continue; + } + addons.push_back(*itr); + ++itr; + } + } + return !addons.empty(); +} + +bool CAddonMgr::GetAddon(const TYPE &type, const CStdString &str, AddonPtr &addon) +{ + CDateTimeSpan span; + span.SetDateTimeSpan(0, 0, 0, ADDON_DIRSCAN_FREQ); + if(!m_lastDirScan[type].IsValid() || (m_lastDirScan[type] + span) < CDateTime::GetCurrentDateTime()) + { + m_lastDirScan[type] = CDateTime::GetCurrentDateTime(); + LoadAddonsXML(type); + } + + if (m_addons.find(type) == m_addons.end()) + return false; + + bool isUUID = StringUtils::ValidateUUID(str); + + VECADDONS &addons = m_addons[type]; + IVECADDONS adnItr = addons.begin(); + while (adnItr != addons.end()) + { + //FIXME scrapers were previously registered by filename + if ( (isUUID && (*adnItr)->UUID() == str) + || (!isUUID && (*adnItr)->Name() == str) + || (type == ADDON_SCRAPER && (*adnItr)->LibName() == str)) + { + addon = (*adnItr); + return true; + } + adnItr++; + } + + return false; +} + +//TODO handle all 'default' cases here, not just scrapers & vizs +bool CAddonMgr::GetDefault(const TYPE &type, AddonPtr &addon, const CONTENT_TYPE &content) +{ + if (type != ADDON_SCRAPER && type != ADDON_VIZ) + return false; + + CStdString setting; + if (type == ADDON_VIZ) + setting = g_guiSettings.GetString("musicplayer.visualisation"); + else + { + switch (content) + { + case CONTENT_MOVIES: + { + setting = g_guiSettings.GetString("scrapers.moviedefault"); + break; + } + case CONTENT_TVSHOWS: + { + setting = g_guiSettings.GetString("scrapers.tvshowdefault"); + break; + } + case CONTENT_MUSICVIDEOS: + { + setting = g_guiSettings.GetString("scrapers.musicvideodefault"); + break; + } + case CONTENT_ALBUMS: + case CONTENT_ARTISTS: + { + setting = g_guiSettings.GetString("musiclibrary.scraper"); + break; + } + default: + return false; + } + } + return GetAddon(type, setting, addon); +} + +CStdString CAddonMgr::GetString(const CStdString &uuid, const int number) +{ + AddonPtr addon = m_uuidMap[uuid]; + if (addon) + return addon->GetString(number); + + return ""; +} + +bool CAddonMgr::EnableAddon(const CStdString &uuid) +{ + AddonPtr addon = m_uuidMap[uuid]; + if (!addon) + { + CLog::Log(LOGINFO,"ADDON: Couldn't find Add-on to Enable: %s", uuid.c_str()); + return false; + } + + return EnableAddon(addon); +} + +bool CAddonMgr::EnableAddon(AddonPtr &addon) +{ + CUtil::CreateDirectoryEx(addon->Profile()); + addon->Enable(); + CLog::Log(LOGINFO,"ADDON: Enabled %s: %s : %s", TranslateType(addon->Type()).c_str(), addon->Name().c_str(), addon->Version().Print().c_str()); + SaveAddonsXML(addon->Type()); + return true; +} + +bool CAddonMgr::DisableAddon(const CStdString &uuid) +{ + AddonPtr addon = m_uuidMap[uuid]; + if (!addon) + return false; + return DisableAddon(addon); +} + +bool CAddonMgr::DisableAddon(AddonPtr &addon) +{ + const TYPE type = addon->Type(); + + if (m_addons.find(type) == m_addons.end()) + return false; + + for (IVECADDONS itr = m_addons[type].begin(); itr != m_addons[type].end(); itr++) + { + if (addon == (*itr)) + { + addon->Disable(); + + if (addon->Parent()) + { // we can delete this cloned addon + m_addons[type].erase(itr); + } + + CLog::Log(LOGINFO,"ADDON: Disabled %s: %s", TranslateType(addon->Type()).c_str(), addon->Name().c_str()); + SaveAddonsXML(type); + return true; + } + } + CLog::Log(LOGINFO,"ADDON: Couldn't find Add-on to Disable: %s", addon->Name().c_str()); + return false; +} + +bool CAddonMgr::LoadAddonsXML(const TYPE &type) +{ + VECADDONPROPS props; + if (!LoadAddonsXML(type, props)) + return false; + + // refresh addon dirs if neccesary/forced + FindAddons(type); + + // now enable accordingly + VECADDONPROPS::const_iterator itr = props.begin(); + while (itr != props.end()) + { + AddonPtr addon; + if (itr->parent.empty() && GetAddon(type, itr->uuid, addon)) + { + EnableAddon(addon); + } + else if (GetAddon(type, itr->parent, addon)) + { // multiple addon configurations + AddonPtr clone = addon->Clone(addon); + if (clone) + { + m_addons[type].push_back(clone); + } + } + else + { // addon not found + CLog::Log(LOGERROR, "ADDON: Couldn't find %s requested. Name: %s", TranslateType(type).c_str(), itr->name.c_str()); + //TODO we should really add but mark unavailable, to prompt user + } + ++itr; + } + return true; +} + +bool CAddonMgr::GetAddonProps(const TYPE &type, VECADDONPROPS &props) +{ + props.clear(); + VECADDONS addons; + bool found = GetAddons(type, addons); + if (found) + { + IVECADDONS itr = addons.begin(); + while (itr != addons.end()) + { + AddonProps addon(*itr); + props.push_back(addon); + ++itr; + } + } + return found; +} + +void CAddonMgr::FindAddons(const TYPE &type) +{ + // parse the user & system dirs for addons of the requested type + CFileItemList items; + bool isHome = CSpecialProtocol::XBMCIsHome(); + + // store any addons with unresolved deps, then recheck at the end + VECADDONS unresolved; + + switch (type) + { + case ADDON_VIZ: + { //TODO fix mvis handling + if (!isHome) + CDirectory::GetDirectory("special://home/addons/visualizations", items, ADDON_VIS_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/visualizations", items, ADDON_VIS_EXT, false); + break; + } + case ADDON_SCREENSAVER: + { + if (!isHome) + CDirectory::GetDirectory("special://home/addons/screensavers", items, ADDON_SCREENSAVER_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/screensavers", items, ADDON_SCREENSAVER_EXT, false); + break; + } + case ADDON_SCRAPER: + { + if (!isHome) + CDirectory::GetDirectory("special://home/addons/scrapers", items, ADDON_SCRAPER_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/scrapers", items, ADDON_SCRAPER_EXT, false); + break; + } + case ADDON_SCRAPER_LIBRARY: + { + if (!isHome) + CDirectory::GetDirectory("special://home/addons/libraries/scrapers", items, ADDON_SCRAPER_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/libraries/scrapers", items, ADDON_SCRAPER_EXT, false); + break; + } + case ADDON_SCRIPT: + { + if (!isHome) + CDirectory::GetDirectory("special://home/addons/scripts", items, ADDON_PYTHON_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/scripts", items, ADDON_PYTHON_EXT, false); + break; + } + case ADDON_PLUGIN: + { + if (!isHome) + CDirectory::GetDirectory("special://home/addons/plugins", items, ADDON_PYTHON_EXT, false); + CDirectory::GetDirectory("special://xbmc/addons/plugins", items, ADDON_PYTHON_EXT, false); + break; + } + default: + return; + } + + //FIXME this only checks library dependencies - multiple addon type deps + //need a more sophisticated approach + if (type == ADDON_SCRAPER) + FindAddons(ADDON_SCRAPER_LIBRARY); + else if (type == ADDON_VIZ) + FindAddons(ADDON_VIZ_LIBRARY); + + // for all folders found + for (int i = 0; i < items.Size(); ++i) + { + CFileItemPtr item = items[i]; + + // read description.xml and populate the addon + AddonPtr addon; + if (!AddonFromInfoXML(type, item->m_strPath, addon)) + { + CLog::Log(LOGDEBUG, "ADDON: Error reading %sdescription.xml, bypassing package", item->m_strPath.c_str()); + continue; + } + + // check for/cache icon thumbnail + //TODO cache one thumb per addon uuid instead + CFileItem item2(addon->Path()); + CUtil::AddFileToFolder(addon->Path(), addon->LibName(), item2.m_strPath); + item2.m_bIsFolder = false; + item2.SetCachedProgramThumb(); + if (!item2.HasThumbnail()) + item2.SetUserProgramThumb(); + if (!item2.HasThumbnail()) + item2.SetThumbnailImage(addon->Icon()); + if (item2.HasThumbnail()) + { + XFILE::CFile::Cache(item2.GetThumbnailImage(),item->GetCachedProgramThumb()); + } + + if (!DependenciesMet(addon)) + { + unresolved.push_back(addon); + continue; + } + else + { // everything ok, add to available addons if new + if (UpdateIfKnown(addon)) + continue; + else + { + assert(addon->Type() == type); + m_addons[type].push_back(addon); + m_uuidMap.insert(std::make_pair(addon->UUID(), addon)); + } + } + } + + for (unsigned i = 0; i < unresolved.size(); i++) + { + AddonPtr& addon = unresolved[i]; + if (DependenciesMet(addon)) + { + if (!UpdateIfKnown(addon)) + { + m_addons[type].push_back(addon); + m_uuidMap.insert(std::make_pair(addon->UUID(), addon)); + } + } + } + CLog::Log(LOGINFO, "ADDON: Found %"PRIuS" addons of type %s", m_addons[type].size(), TranslateType(type).c_str()); +} + +bool CAddonMgr::UpdateIfKnown(AddonPtr &addon) +{ + if (m_addons.find(addon->Type()) != m_addons.end()) + { + for (unsigned i = 0; i < m_addons[addon->Type()].size(); i++) + { + if (m_addons[addon->Type()][i]->UUID() == addon->UUID()) + { + //TODO inform any manager first, and request removal + //TODO choose most recent version if varying + m_addons[addon->Type()][i] = addon; + CStdString uuid = addon->UUID(); + m_uuidMap.erase(uuid); + m_uuidMap.insert(std::make_pair(addon->UUID(), addon)); + return true; + } + } + } + return false; +} + +bool CAddonMgr::DependenciesMet(AddonPtr &addon) +{ + // As remote repos are not functioning, + // this will fail if a dependency is not found locally + if (!addon) + return false; + + ADDONDEPS deps = addon->GetDeps(); + ADDONDEPS::iterator itr = deps.begin(); + while (itr != deps.end()) + { + CStdString uuid; + uuid = (*itr).first; + AddonVersion min = (*itr).second.first; + AddonVersion max = (*itr).second.second; + if (m_uuidMap.count(uuid)) + { + AddonPtr dep = m_uuidMap[uuid]; + // we're guaranteed to have at least max OR min here + if (!min.str.IsEmpty() && !max.str.IsEmpty()) + return (dep->Version() >= min && dep->Version() <= max); + else if (!min.str.IsEmpty()) + return (dep->Version() >= min); + else + return (dep->Version() <= max); + } + for (unsigned i=0; i < m_remoteAddons.size(); i++) + { + if (m_remoteAddons[i].uuid == uuid) + { + if(m_remoteAddons[i].version >= min && m_remoteAddons[i].version <= max) + { + //TODO line up download + return false; + } + } + } + itr++; + } + return deps.empty(); +} + +bool CAddonMgr::AddonFromInfoXML(const TYPE &reqType, const CStdString &path, AddonPtr &addon) +{ + // First check that we can load description.xml + CStdString strPath(path); + CUtil::AddFileToFolder(strPath, ADDON_METAFILE, strPath); + + TiXmlDocument xmlDoc; + if (!xmlDoc.LoadFile(strPath)) + { + CLog::Log(LOGERROR, "Unable to load: %s, Line %d\n%s", strPath.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc()); + return false; + } + + TiXmlElement *element = xmlDoc.RootElement(); + if (!element || strcmpi(element->Value(), "addoninfo") != 0) + { + CLog::Log(LOGERROR, "ADDON: Error loading %s: cannot find <addon> root element", strPath.c_str()); + return false; + } + + /* Steps required to meet package requirements + * 1. uuid exists and is valid + * 2. type exists and is valid + * 3. version exists + * 4. a license is specified + * 5. operating system matches ours + * 6. summary exists + * 7. for scrapers & plugins, support at least one type of content + * + * NOTE: addon dependencies are handled in ::FindAddons() + */ + + /* Read uuid */ + CStdString uuid; + element = xmlDoc.RootElement()->FirstChildElement("uuid"); + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s does not contain the <uuid> element, ignoring", strPath.c_str()); + return false; + } + uuid = element->GetText(); + + /* Validate type */ + element = xmlDoc.RootElement()->FirstChildElement("type"); + TYPE type = TranslateType(element->GetText()); + if (type != reqType) + { + CLog::Log(LOGERROR, "ADDON: %s has invalid type identifier: '%d'", strPath.c_str(), type); + return false; + } + + /* Validate uuid */ + if (!StringUtils::ValidateUUID(uuid)) + { + CLog::Log(LOGERROR, "ADDON: %s has invalid <uuid> element, ignoring", strPath.c_str()); + return false; + } + + /* Retrieve Name */ + CStdString name; + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("title"); + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <title> element, ignoring", strPath.c_str()); + return false; + } + name = element->GetText(); + + /* Retrieve version */ + CStdString version; + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("version"); + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <version> element, ignoring", strPath.c_str()); + return false; + } + /* Validate version */ + version = element->GetText(); + CRegExp versionRE; + versionRE.RegComp(ADDON_VERSION_RE.c_str()); + if (versionRE.RegFind(version.c_str()) != 0) + { + CLog::Log(LOGERROR, "ADDON: %s has invalid <version> element, ignoring", strPath.c_str()); + return false; + } + + /* Path, UUID & Version are valid */ + AddonProps addonProps(uuid, type, version); + addonProps.name = name; + addonProps.path = path; + addonProps.icon = CUtil::AddFileToFolder(path, "default.tbn"); + + /* Retrieve license */ + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("license"); +/* if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <license> element, ignoring", strPath.c_str()); + return false; + } + addonProps.license = element->GetText();*/ + + /* Retrieve platforms which this addon supports */ + CStdString platform; + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("platforms")->FirstChildElement("platform"); + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <platforms> element, ignoring", strPath.c_str()); + return false; + } + + bool all(false); + std::set<CStdString> platforms; + do + { + CStdString platform = element->GetText(); + if (platform == "all") + { + all = true; + break; + } + platforms.insert(platform); + element = element->NextSiblingElement("platform"); + } while (element != NULL); + + if (!all) + { +#if defined(_LINUX) && !defined(__APPLE__) + if (!platforms.count("linux")) + { + CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Linux, ignoring", strPath.c_str()); + return false; + } +#elif defined(_WIN32) + if (!platforms.count("windows")) + { + CLog::Log(LOGNOTICE, "ADDON: %s is not supported under Windows, ignoring", strPath.c_str()); + return false; + } +#elif defined(__APPLE__) + if (!platforms.count("osx")) + { + CLog::Log(LOGNOTICE, "ADDON: %s is not supported under OSX, ignoring", strPath.c_str()); + return false; + } +#elif defined(_XBOX) + if (!platforms.count("xbox")) + { + CLog::Log(LOGNOTICE, "ADDON: %s is not supported under XBOX, ignoring", strPath.c_str()); + return false; + } +#endif + } + + /* Retrieve summary */ + CStdString summary; + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("summary"); + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <summary> element, ignoring", strPath.c_str()); + return false; + } + addonProps.summary = element->GetText(); + + if (addonProps.type == ADDON_SCRAPER || addonProps.type == ADDON_PLUGIN) + { + /* Retrieve content types that this addon supports */ + CStdString platform; + element = NULL; + if (xmlDoc.RootElement()->FirstChildElement("supportedcontent")) + { + element = xmlDoc.RootElement()->FirstChildElement("supportedcontent")->FirstChildElement("content"); + } + if (!element) + { + CLog::Log(LOGERROR, "ADDON: %s missing <supportedcontent> element, ignoring", strPath.c_str()); + return false; + } + + std::set<CONTENT_TYPE> contents; + do + { + CONTENT_TYPE content = TranslateContent(element->GetText()); + if (content != CONTENT_NONE) + { + contents.insert(content); + } + element = element->NextSiblingElement("content"); + } while (element != NULL); + + if (contents.empty()) + { + CLog::Log(LOGERROR, "ADDON: %s %s supports no available content-types, ignoring", TranslateType(addonProps.type).c_str(), addonProps.name.c_str()); + return false; + } + else + { + addonProps.contents = contents; + } + } + + /*** Beginning of optional fields ***/ + /* Retrieve description */ + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("description"); + if (element) + addonProps.description = element->GetText(); + + /* Retrieve author */ + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("author"); + if (element) + addonProps.author = element->GetText(); + + /* Retrieve disclaimer */ + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("disclaimer"); + if (element) + addonProps.disclaimer = element->GetText(); + + /* Retrieve library file name */ + // will be replaced with default library name if unspecified + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("library"); + if (element) + addonProps.libname = element->GetText(); + + //TODO move this to addon specific class, if it's needed at all.. +#ifdef _WIN32 + /* Retrieve WIN32 library file name in case it is present + * This is required for no overwrite to the fixed WIN32 add-on's + * during compile time + */ + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("librarywin32"); + if (element) // If it is found overwrite standard library name + addonProps.libname = element->GetText(); +#endif + + /* Retrieve dependencies that this addon requires */ + std::map<CStdString, std::pair<const AddonVersion, const AddonVersion> > deps; + element = NULL; + element = xmlDoc.RootElement()->FirstChildElement("dependencies"); + if (element) + { + element = element->FirstChildElement("dependency"); + if (!element) + CLog::Log(LOGDEBUG, "ADDON: %s missing at least one <dependency> element, will ignore this dependency", strPath.c_str()); + else + { + do + { + CStdString min = element->Attribute("minversion"); + CStdString max = element->Attribute("maxversion"); + CStdString uuid = element->GetText(); + if (!uuid || (!min && ! max)) + { + CLog::Log(LOGDEBUG, "ADDON: %s malformed <dependency> element, will ignore this dependency", strPath.c_str()); + continue; + } + deps.insert(std::make_pair(uuid, std::make_pair(AddonVersion(min), AddonVersion(max)))); + element = element->NextSiblingElement("dependency"); + } while (element != NULL); + } + } + + /*** end of optional fields ***/ + + /* Create an addon object and store in a shared_ptr */ + addon.reset(); + switch (type) + { + case ADDON_PLUGIN: + case ADDON_SCRIPT: + { + AddonPtr temp(new CAddon(addonProps)); + addon = temp; + break; + } + case ADDON_SCRAPER: + { + AddonPtr temp(new CScraper(addonProps)); + addon = temp; + break; + } + case ADDON_VIZ: + { + AddonPtr temp(new CVisualisation(addonProps)); + addon = temp; + break; + } + case ADDON_SCREENSAVER: + { + AddonPtr temp(new CScreenSaver(addonProps)); + addon = temp; + break; + } + case ADDON_SCRAPER_LIBRARY: + case ADDON_VIZ_LIBRARY: + { + AddonPtr temp(new CAddonLibrary(addonProps)); + addon = temp; + break; + } + default: + return false; + } + + addon->SetDeps(deps); + return true; +} + +CStdString CAddonMgr::GetAddonsXMLFile() const +{ + CStdString folder; + if (g_settings.m_vecProfiles[g_settings.m_iLastLoadedProfileIndex].hasAddons()) + CUtil::AddFileToFolder(g_settings.GetProfileUserDataFolder(),"addons.xml",folder); + else + CUtil::AddFileToFolder(g_settings.GetUserDataFolder(),"addons.xml",folder); + + return folder; +} + +bool CAddonMgr::SaveAddonsXML(const TYPE &type) +{ + VECADDONPROPS props; + GetAddonProps(type, props); + + // TODO: Should we be specifying utf8 here?? + TiXmlDocument doc; + if (!doc.LoadFile(GetAddonsXMLFile())) + doc.ClearError(); + + // either point to existing addons node, or create one + TiXmlNode *pRoot = NULL; + pRoot = doc.FirstChildElement("addons"); + if (!pRoot) + { + TiXmlElement xmlRootElement("addons"); + pRoot = doc.InsertEndChild(xmlRootElement); + if (!pRoot) + return false; + } + + // ok, now run through and save the modified addons section + SetAddons(pRoot, type, props); + + return doc.SaveFile(GetAddonsXMLFile()); +} + +bool CAddonMgr::SetAddons(TiXmlNode *root, const TYPE &type, const VECADDONPROPS &addons) +{ + CStdString strType; + strType = TranslateType(type); + + if (strType.IsEmpty()) + return false; + + TiXmlElement sectionElement(strType); + TiXmlNode *sectionNode = root->FirstChild(strType); + + if (sectionNode) + { // must delete the original section before regenerating + root->RemoveChild(sectionNode); + } + if (!addons.empty()) + { // only recreate the sectionNode if there's addons of this type enabled + sectionNode = root->InsertEndChild(sectionElement); + + VECADDONPROPS::const_iterator itr = addons.begin(); + while (itr != addons.end()) + { + TiXmlElement element("addon"); + XMLUtils::SetString(&element, "uuid", itr->uuid); + if (!itr->parent.IsEmpty()) + XMLUtils::SetString(&element, "parentuuid", itr->parent); + sectionNode->InsertEndChild(element); + ++itr; + } + } + return true; +} + +bool CAddonMgr::LoadAddonsXML(const TYPE &type, VECADDONPROPS &addons) +{ + CStdString strXMLFile; + TiXmlDocument xmlDoc; + TiXmlElement *pRootElement = NULL; + strXMLFile = GetAddonsXMLFile(); + CLog::Log(LOGNOTICE, "ADDONS: Attempting to parse %s", strXMLFile.c_str()); + if ( xmlDoc.LoadFile( strXMLFile ) ) + { + pRootElement = xmlDoc.RootElement(); + CStdString strValue; + if (pRootElement) + strValue = pRootElement->Value(); + if ( strValue != "addons") + { + CLog::Log(LOGERROR, "ADDONS: %s does not contain <addons> element", strXMLFile.c_str()); + return false; + } + } + else if (CFile::Exists(strXMLFile)) + { + CLog::Log(LOGERROR, "ADDONS: Error loading %s: Line %d, %s", strXMLFile.c_str(), xmlDoc.ErrorRow(), xmlDoc.ErrorDesc()); + return false; + } + else + { + CLog::Log(LOGINFO, "ADDONS: No addons.xml found"); + return true; // no addons enabled for this profile yet + } + + if (pRootElement) + { // parse addons... + GetAddons(pRootElement, type, addons); + return true; + } + + return false; +} + +void CAddonMgr::GetAddons(const TiXmlElement* pRootElement, const TYPE &type, VECADDONPROPS &addons) +{ + CStdString strTagName; + strTagName = TranslateType(type); + + const TiXmlNode *pChild = pRootElement->FirstChild(strTagName.c_str()); + if (pChild) + { + pChild = pChild->FirstChild(); + while (pChild > 0) + { + CStdString strValue = pChild->Value(); + if (strValue == "addon") + { + GetAddon(type, pChild, addons); + } + pChild = pChild->NextSibling(); + } + } + else + { + CLog::Log(LOGDEBUG, "ADDONS: <%s> tag is missing or addons.xml is malformed", strTagName.c_str()); + } +} + +bool CAddonMgr::GetAddon(const TYPE &type, const TiXmlNode *node, VECADDONPROPS &addons) +{ + // uuid + const TiXmlNode *pNodePath = node->FirstChild("uuid"); + CStdString uuid; + if (pNodePath && pNodePath->FirstChild()) + { + uuid = pNodePath->FirstChild()->Value(); + } + else + return false; + + // this AddonProps doesn't need a valid version + CStdString version; + AddonProps props(uuid, type, version); + + // name if present + const TiXmlNode *pNodeName = node->FirstChild("name"); + CStdString strName; + if (pNodeName && pNodeName->FirstChild()) + { + props.name = pNodeName->FirstChild()->Value(); + } + + // parent uuid if present + const TiXmlNode *pNodeChildGUID = node->FirstChild("parentuuid"); + if (pNodeChildGUID && pNodeChildGUID->FirstChild()) + { + props.parent = pNodeChildGUID->FirstChild()->Value(); + } + + // get custom thumbnail + const TiXmlNode *pThumbnailNode = node->FirstChild("thumbnail"); + if (pThumbnailNode && pThumbnailNode->FirstChild()) + { + props.icon = pThumbnailNode->FirstChild()->Value(); + } + + addons.insert(addons.end(), props); + return true; +} + +} /* namespace ADDON */ + diff --git a/xbmc/utils/AddonManager.h b/xbmc/utils/AddonManager.h new file mode 100644 index 0000000000..ee546f9798 --- /dev/null +++ b/xbmc/utils/AddonManager.h @@ -0,0 +1,151 @@ +#pragma once +/* + * Copyright (C) 2005-2009 Team XBMC + * http://www.xbmc.org + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with XBMC; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * http://www.gnu.org/copyleft/gpl.html + * + */ +#include "Addon.h" +#include "../addons/include/xbmc_addon_dll.h" +#include "tinyXML/tinyxml.h" +#include "Thread.h" +#include "StdString.h" +#include "DateTime.h" +#include "DownloadQueue.h" +#include <vector> +#include <map> + +class CCriticalSection; + +namespace ADDON +{ + typedef std::vector<AddonPtr> VECADDONS; + typedef std::vector<AddonPtr>::iterator IVECADDONS; + typedef std::map<TYPE, VECADDONS> MAPADDONS; + + const int ADDON_DIRSCAN_FREQ = 300; + const CStdString ADDON_XBMC_REPO_URL = "http://mirrors.xbmc.org/addons/addons.xml"; + const CStdString ADDON_METAFILE = "description.xml"; + const CStdString ADDON_VIS_EXT = "*.vis"; + const CStdString ADDON_PYTHON_EXT = "*.py"; + const CStdString ADDON_SCRAPER_EXT = "*.xml"; + const CStdString ADDON_SCREENSAVER_EXT = "*.xbs"; + const CStdString ADDON_DSP_AUDIO_EXT = "*.adsp"; + const CStdString ADDON_VERSION_RE = "(?<Major>\\d*)\\.?(?<Minor>\\d*)?\\.?(?<Build>\\d*)?\\.?(?<Revision>\\d*)?"; + + /** + * Class - IAddonCallback + * This callback should be inherited by any class which manages + * specific addon types. Could be mostly used for Dll addon types to handle + * cleanup before restart/removal + */ + class IAddonMgrCallback + { + public: + virtual bool RequestRestart(const IAddon* addon, bool datachanged)=0; + virtual bool RequestRemoval(const IAddon* addon)=0; + }; + + /** + * Class - CAddonStatusHandler + * Used to informate the user about occurred errors and + * changes inside Add-on's, and ask him what to do. + * It can executed in the same thread as the calling + * function or in a seperate thread. + */ + class CAddonStatusHandler : private CThread + { + public: + CAddonStatusHandler(IAddon* const addon, ADDON_STATUS status, CStdString message, bool sameThread = true); + ~CAddonStatusHandler(); + + /* Thread handling */ + virtual void Process(); + virtual void OnStartup(); + virtual void OnExit(); + + private: + static CCriticalSection m_critSection; + IAddon* m_addon; + ADDON_STATUS m_status; + CStdString m_message; + }; + + /** + * Class - CAddonMgr + * Holds references to all addons, enabled or + * otherwise. Services the generic callbacks available + * to all addon variants. + */ + class CAddonMgr : public IDownloadQueueObserver + { + public: + static CAddonMgr* Get(); + virtual ~CAddonMgr(); + + IAddonMgrCallback* GetCallbackForType(TYPE type); + bool RegisterAddonMgrCallback(TYPE type, IAddonMgrCallback* cb); + void UnregisterAddonMgrCallback(TYPE type); + + /* Addon access */ + bool GetDefault(const TYPE &type, AddonPtr &addon, const CONTENT_TYPE &content = CONTENT_NONE); + bool GetAddon(const TYPE &type, const CStdString &str, AddonPtr &addon); + bool HasAddons(const TYPE &type, const CONTENT_TYPE &content = CONTENT_NONE); + bool GetAddons(const TYPE &type, VECADDONS &addons, const CONTENT_TYPE &content = CONTENT_NONE, bool enabled = true); + bool GetAllAddons(VECADDONS &addons, bool enabledOnly = true); + CStdString GetString(const CStdString &uuid, const int number); + + /* Addon operations */ + bool EnableAddon(AddonPtr &addon); + bool EnableAddon(const CStdString &uuid); + bool DisableAddon(AddonPtr &addon); + bool DisableAddon(const CStdString &uuid); + bool Clone(const AddonPtr& parent, AddonPtr& child); + + private: + /* Addon Repositories */ + virtual void OnFileComplete(TICKET aTicket, CStdString& aFilePath, INT aByteRxCount, Result aResult); + std::vector<TICKET> m_downloads; + VECADDONPROPS m_remoteAddons; + void UpdateRepos(); + bool ParseRepoXML(const CStdString &path); + + void FindAddons(const TYPE &type); + bool LoadAddonsXML(const TYPE &type); + bool SaveAddonsXML(const TYPE &type); + bool AddonFromInfoXML(const TYPE &reqType, const CStdString &path, AddonPtr &addon); + bool DependenciesMet(AddonPtr &addon); + bool UpdateIfKnown(AddonPtr &addon); + + /* addons.xml */ + CStdString GetAddonsXMLFile() const; + bool GetAddonProps(const TYPE &type, VECADDONPROPS &addons); + bool LoadAddonsXML(const TYPE& type, VECADDONPROPS& addons); + bool SaveAddonsXML(const TYPE& type, const VECADDONPROPS &addons); + bool SetAddons(TiXmlNode *root, const TYPE &type, const VECADDONPROPS &addons); + void GetAddons(const TiXmlElement* pRootElement, const TYPE &type, VECADDONPROPS &addons); + bool GetAddon(const TYPE &type, const TiXmlNode *node, VECADDONPROPS &addon); + + CAddonMgr(); + static CAddonMgr* m_pInstance; + static std::map<TYPE, IAddonMgrCallback*> m_managers; + MAPADDONS m_addons; + std::map<TYPE, CDateTime> m_lastDirScan; + std::map<CStdString, AddonPtr> m_uuidMap; + }; + +}; /* namespace ADDON */ diff --git a/xbmc/utils/Builtins.cpp b/xbmc/utils/Builtins.cpp index c2f3efc715..ba6e49b74b 100644 --- a/xbmc/utils/Builtins.cpp +++ b/xbmc/utils/Builtins.cpp @@ -37,6 +37,7 @@ #include "GUIUserMessages.h" #include "GUIWindowLoginScreen.h" #include "GUIWindowVideoBase.h" +#include "Addon.h" // for TranslateType, TranslateContent #include "LastFmManager.h" #include "LCD.h" #include "log.h" @@ -927,30 +928,43 @@ int CBuiltins::Execute(const CStdString& execString) } else if (execute.Equals("skin.setfile")) { + // Note. can only browse one addon type from here + // if browsing for addons, required param[1] is addontype string, with optional param[2] + // as contenttype string see IAddon.h & ADDON::TranslateXX CStdString strMask = (params.size() > 1) ? params[1] : ""; - if (strMask.Find(".py") > -1) + strMask.ToLower(); + ADDON::TYPE type; + if ((type = ADDON::TranslateType(strMask)) != ADDON::ADDON_UNKNOWN) { - CMediaSource source; - source.strPath = "special://home/scripts/"; - source.strName = g_localizeStrings.Get(247); - localShares.push_back(source); + CURL url; + url.SetProtocol("addons"); + url.SetHostName(strMask); + localShares.clear(); + CStdString content = (params.size() > 2) ? params[2] : ""; + content.ToLower(); + url.SetPassword(content); + CStdString replace; + if (CGUIDialogFileBrowser::ShowAndGetFile(url.Get(), "", TranslateType(type, true), replace, true, true)) + g_settings.SetSkinString(string, replace); } - - if (params.size() > 2) + else { - value = params[2]; - CUtil::AddSlashAtEnd(value); - bool bIsSource; - if (CUtil::GetMatchingSource(value,localShares,bIsSource) < 0) // path is outside shares - add it as a separate one + if (params.size() > 2) { - CMediaSource share; - share.strName = g_localizeStrings.Get(13278); - share.strPath = value; - localShares.push_back(share); + value = params[2]; + CUtil::AddSlashAtEnd(value); + bool bIsSource; + if (CUtil::GetMatchingSource(value,localShares,bIsSource) < 0) // path is outside shares - add it as a separate one + { + CMediaSource share; + share.strName = g_localizeStrings.Get(13278); + share.strPath = value; + localShares.push_back(share); + } } + if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, g_localizeStrings.Get(1033), value)) + g_settings.SetSkinString(string, value); } - if (CGUIDialogFileBrowser::ShowAndGetFile(localShares, strMask, g_localizeStrings.Get(1033), value)) - g_settings.SetSkinString(string, value); } else // execute.Equals("skin.setpath")) { @@ -1037,10 +1051,7 @@ int CBuiltins::Execute(const CStdString& execString) if (scanner->IsScanning()) scanner->StopScanning(); else - { - SScraperInfo info; - CGUIWindowVideoBase::OnScan(params.size() > 1 ? params[1] : "",info,settings); - } + CGUIWindowVideoBase::OnScan(params.size() > 1 ? params[1] : "",ADDON::ScraperPtr(),settings); } } } diff --git a/xbmc/utils/DownloadQueue.cpp b/xbmc/utils/DownloadQueue.cpp index df61c03a88..eff3c46791 100644 --- a/xbmc/utils/DownloadQueue.cpp +++ b/xbmc/utils/DownloadQueue.cpp @@ -51,7 +51,7 @@ CDownloadQueue::~CDownloadQueue(void) } -TICKET CDownloadQueue::RequestContent(CStdString& aUrl, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueue::RequestContent(const CStdString& aUrl, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); @@ -64,7 +64,7 @@ TICKET CDownloadQueue::RequestContent(CStdString& aUrl, IDownloadQueueObserver* return request.ticket; } -TICKET CDownloadQueue::RequestFile(CStdString& aUrl, CStdString& aFilePath, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueue::RequestFile(const CStdString& aUrl, const CStdString& aFilePath, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); @@ -97,7 +97,7 @@ void CDownloadQueue::CancelRequests(IDownloadQueueObserver *aObserver) LeaveCriticalSection(&m_critical); } -TICKET CDownloadQueue::RequestFile(CStdString& aUrl, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueue::RequestFile(const CStdString& aUrl, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); diff --git a/xbmc/utils/DownloadQueue.h b/xbmc/utils/DownloadQueue.h index a1d6c2656b..bbbda88aae 100644 --- a/xbmc/utils/DownloadQueue.h +++ b/xbmc/utils/DownloadQueue.h @@ -52,9 +52,9 @@ public: CDownloadQueue(); virtual ~CDownloadQueue(void); - TICKET RequestContent(CStdString& aUrl, IDownloadQueueObserver* aObserver); - TICKET RequestFile(CStdString& aUrl, IDownloadQueueObserver* aObserver); - TICKET RequestFile(CStdString& aUrl, CStdString& aFilePath, IDownloadQueueObserver* aObserver); + TICKET RequestContent(const CStdString& aUrl, IDownloadQueueObserver* aObserver); + TICKET RequestFile(const CStdString& aUrl, IDownloadQueueObserver* aObserver); + TICKET RequestFile(const CStdString& aUrl, const CStdString& aFilePath, IDownloadQueueObserver* aObserver); void CancelRequests(IDownloadQueueObserver* aObserver); VOID Flush(); diff --git a/xbmc/utils/DownloadQueueManager.cpp b/xbmc/utils/DownloadQueueManager.cpp index a9964a679e..95aa50b9c9 100644 --- a/xbmc/utils/DownloadQueueManager.cpp +++ b/xbmc/utils/DownloadQueueManager.cpp @@ -41,7 +41,7 @@ VOID CDownloadQueueManager::Initialize() } -TICKET CDownloadQueueManager::RequestContent(CStdString& aUrl, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueueManager::RequestContent(const CStdString& aUrl, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); TICKET ticket = GetNextDownloadQueue()->RequestContent(aUrl, aObserver); @@ -49,7 +49,7 @@ TICKET CDownloadQueueManager::RequestContent(CStdString& aUrl, IDownloadQueueObs return ticket; } -TICKET CDownloadQueueManager::RequestFile(CStdString& aUrl, CStdString& aFilePath, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueueManager::RequestFile(const CStdString& aUrl, const CStdString& aFilePath, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); TICKET ticket = GetNextDownloadQueue()->RequestFile(aUrl, aFilePath, aObserver); @@ -57,7 +57,7 @@ TICKET CDownloadQueueManager::RequestFile(CStdString& aUrl, CStdString& aFilePat return ticket; } -TICKET CDownloadQueueManager::RequestFile(CStdString& aUrl, IDownloadQueueObserver* aObserver) +TICKET CDownloadQueueManager::RequestFile(const CStdString& aUrl, IDownloadQueueObserver* aObserver) { EnterCriticalSection(&m_critical); TICKET ticket = GetNextDownloadQueue()->RequestFile(aUrl, aObserver); diff --git a/xbmc/utils/DownloadQueueManager.h b/xbmc/utils/DownloadQueueManager.h index 25b96a4225..4474f97144 100644 --- a/xbmc/utils/DownloadQueueManager.h +++ b/xbmc/utils/DownloadQueueManager.h @@ -32,9 +32,9 @@ public: virtual ~CDownloadQueueManager(void); VOID Initialize(); - TICKET RequestContent(CStdString& aUrl, IDownloadQueueObserver* aObserver); - TICKET RequestFile(CStdString& aUrl, IDownloadQueueObserver* aObserver); - TICKET RequestFile(CStdString& aUrl, CStdString& aFilePath, IDownloadQueueObserver* aObserver); + TICKET RequestContent(const CStdString& aUrl, IDownloadQueueObserver* aObserver); + TICKET RequestFile(const CStdString& aUrl, IDownloadQueueObserver* aObserver); + TICKET RequestFile(const CStdString& aUrl, const CStdString& aFilePath, IDownloadQueueObserver* aObserver); void CancelRequests(IDownloadQueueObserver *aObserver); protected: diff --git a/xbmc/utils/GUIInfoManager.cpp b/xbmc/utils/GUIInfoManager.cpp index d6c083b046..af7a0b45ff 100644 --- a/xbmc/utils/GUIInfoManager.cpp +++ b/xbmc/utils/GUIInfoManager.cpp @@ -79,6 +79,7 @@ using namespace std; using namespace XFILE; using namespace MUSIC_INFO; +using ADDON::CVisualisation; CGUIInfoManager g_infoManager; @@ -1513,25 +1514,18 @@ CStdString CGUIInfoManager::GetLabel(int info, int contextWindow) g_windowManager.SendMessage(msg); if (msg.GetPointer()) { - CVisualisation *pVis = (CVisualisation *)msg.GetPointer(); - char *preset = pVis->GetPreset(); - if (preset) + CVisualisation* viz = NULL; + viz = (CVisualisation*)msg.GetPointer(); + if (viz) { - strLabel = preset; + strLabel = viz->GetPresetName(); CUtil::RemoveExtension(strLabel); } } } break; case VISUALISATION_NAME: - { - strLabel = g_guiSettings.GetString("musicplayer.visualisation"); - if (strLabel != "None" && strLabel.size() > 4) - { // make it look pretty - strLabel = strLabel.Left(strLabel.size() - 4); - strLabel[0] = toupper(strLabel[0]); - } - } + strLabel = g_guiSettings.GetString("musicplayer.visualisation"); break; case FANART_COLOR1: { diff --git a/xbmc/utils/IAddon.h b/xbmc/utils/IAddon.h new file mode 100644 index 0000000000..fc603d2e25 --- /dev/null +++ b/xbmc/utils/IAddon.h @@ -0,0 +1,111 @@ +#pragma once +/* +* Copyright (C) 2005-2009 Team XBMC +* http://www.xbmc.org +* +* This Program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This Program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with XBMC; see the file COPYING. If not, write to +* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +* http://www.gnu.org/copyleft/gpl.html +* +*/ +#include "boost/shared_ptr.hpp" +#include "StdString.h" +#include <set> +#include <map> + +class TiXmlElement; + +typedef enum +{ + CONTENT_PLUGIN = -2, //TODO ditch this, used in scraping code + //TODO -1 is used as default in QueryParams.h + CONTENT_NONE = 0, + CONTENT_MOVIES = 1, + CONTENT_TVSHOWS = 2, + CONTENT_MUSICVIDEOS = 3, + CONTENT_EPISODES = 4, + CONTENT_ALBUMS = 6, + CONTENT_ARTISTS = 7, + CONTENT_PROGRAMS = 8, + CONTENT_PICTURES = 9 +} CONTENT_TYPE; + +namespace ADDON +{ + typedef enum + { + ADDON_UNKNOWN, + ADDON_VIZ, + ADDON_VIZ_LIBRARY, + ADDON_SKIN, + ADDON_PVRDLL, + ADDON_SCRIPT, + ADDON_SCRAPER, + ADDON_SCRAPER_LIBRARY, + ADDON_SCREENSAVER, + ADDON_PLUGIN + } TYPE; + + class IAddon; + typedef boost::shared_ptr<IAddon> AddonPtr; + class CVisualisation; + typedef boost::shared_ptr<CVisualisation> VizPtr; + + class CAddonMgr; + struct AddonVersion; + typedef std::map<CStdString, std::pair<const AddonVersion, const AddonVersion> > ADDONDEPS; + struct AddonProps; + + class IAddon + { + public: + virtual AddonPtr Clone(const AddonPtr& self) const =0; + virtual const TYPE Type() const =0; + virtual AddonProps Props() const =0; + virtual const CStdString UUID() const =0; + virtual const AddonPtr Parent() const =0; + virtual const CStdString Name() const =0; + virtual bool Disabled() const =0; + virtual const AddonVersion Version() =0; + virtual const CStdString Summary() const =0; + virtual const CStdString Description() const =0; + virtual const CStdString Path() const =0; + virtual const CStdString Profile() const =0; + virtual const CStdString LibName() const =0; + virtual const CStdString Author() const =0; + virtual const CStdString Icon() const =0; + virtual const int Stars() const =0; + virtual const CStdString Disclaimer() const =0; + virtual bool Supports(const CONTENT_TYPE &content) const =0; + virtual bool HasSettings() =0; + virtual bool LoadSettings() =0; + virtual void SaveSettings() =0; + virtual void SaveFromDefault() =0; + virtual void UpdateSetting(const CStdString& key, const CStdString& value, const CStdString &type = "") =0; + virtual CStdString GetSetting(const CStdString& key) const =0; + virtual TiXmlElement* GetSettingsXML() =0; + virtual CStdString GetString(uint32_t id) const =0; + virtual ADDONDEPS GetDeps() =0; + + private: + friend class CAddonMgr; + virtual bool IsAddonLibrary() =0; + virtual void Enable() =0; + virtual void Disable() =0; + virtual bool LoadStrings() =0; + virtual void ClearStrings() =0; + virtual void SetDeps(ADDONDEPS& deps) =0; + }; +}; + diff --git a/xbmc/utils/IMDB.cpp b/xbmc/utils/IMDB.cpp index cb74bf9246..2d4c5ebfdd 100644 --- a/xbmc/utils/IMDB.cpp +++ b/xbmc/utils/IMDB.cpp @@ -65,11 +65,11 @@ int CIMDB::InternalFindMovie(const CStdString &strMovie, IMDB_MOVIELIST& movieli movieTitle.ToLower(); - if (m_info.strContent.Equals("musicvideos")) + if (m_info->Content() == CONTENT_MUSICVIDEOS) movieTitle.Replace("-"," "); - CLog::Log(LOGDEBUG, "scraper: Searching for '%s' using %s scraper (file: '%s', content: '%s', language: '%s', date: '%s', framework: '%s')", - movieTitle.c_str(), m_info.strTitle.c_str(), m_info.strPath.c_str(), m_info.strContent.c_str(), m_info.strLanguage.c_str(), m_info.strDate.c_str(), m_info.strFramework.c_str()); + CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper (file: '%s', content: '%s')", + __FUNCTION__, movieTitle.c_str(), m_info->Name().c_str(), m_info->Path().c_str(), ADDON::TranslateContent(m_info->Content()).c_str()); if (!pUrl) { @@ -77,7 +77,7 @@ int CIMDB::InternalFindMovie(const CStdString &strMovie, IMDB_MOVIELIST& movieli { GetURL(strMovie, movieTitle, movieYear, scrURL); } - else if (m_info.strContent.Equals("musicvideos")) + else if (m_info->Content() == CONTENT_MUSICVIDEOS) { if (!m_parser.HasFunction("FileNameScrape")) return false; @@ -107,7 +107,7 @@ int CIMDB::InternalFindMovie(const CStdString &strMovie, IMDB_MOVIELIST& movieli for (unsigned int i=0;i<strHTML.size();++i) m_parser.m_param[i] = strHTML[i]; m_parser.m_param[strHTML.size()] = scrURL.m_url[0].m_url; - CStdString strXML = m_parser.Parse(strFunction,&m_info.settings); + CStdString strXML = m_parser.Parse(strFunction); CLog::Log(LOGDEBUG,"scraper: %s returned %s",strFunction.c_str(),strXML.c_str()); if (strXML.IsEmpty()) { @@ -260,7 +260,7 @@ bool CIMDB::InternalGetEpisodeList(const CScraperUrl& url, IMDB_EPISODELIST& det m_parser.m_param[0] = strHTML; m_parser.m_param[1] = url.m_url[i].m_url; - CStdString strXML = m_parser.Parse("GetEpisodeList",&m_info.settings); + CStdString strXML = m_parser.Parse("GetEpisodeList"); CLog::Log(LOGDEBUG,"scraper: GetEpisodeList returned %s",strXML.c_str()); if (strXML.IsEmpty()) { @@ -382,7 +382,7 @@ bool CIMDB::InternalGetDetails(const CScraperUrl& url, CVideoInfoTag& movieDetai m_parser.m_param[strHTML.size()] = url.strId; m_parser.m_param[strHTML.size()+1] = url.m_url[0].m_url; - CStdString strXML = m_parser.Parse(strFunction,&m_info.settings); + CStdString strXML = m_parser.Parse(strFunction); CLog::Log(LOGDEBUG,"scraper: %s returned %s",strFunction.c_str(),strXML.c_str()); if (strXML.IsEmpty()) { @@ -468,7 +468,7 @@ void CIMDB::GetURL(const CStdString &movieFile, const CStdString &movieName, con g_charsetConverter.utf8To(m_parser.GetSearchStringEncoding(), movieName, m_parser.m_param[0]); CUtil::URLEncode(m_parser.m_param[0]); - scrURL.ParseString(m_parser.Parse("CreateSearchUrl",&m_info.settings)); + scrURL.ParseString(m_parser.Parse("CreateSearchUrl")); } // threaded functions @@ -482,7 +482,7 @@ void CIMDB::Process() if (!(m_found=FindMovie(m_strMovie, m_movieList))) { // retry without replacing '.' and '-' if searching for a tvshow - if (m_info.strContent.Equals("tvshows")) + if (m_info->Content() == CONTENT_TVSHOWS) CLog::Log(LOGERROR, "%s: Error looking up tvshow %s", __FUNCTION__, m_strMovie.c_str()); else CLog::Log(LOGERROR, "%s: Error looking up movie %s", __FUNCTION__, m_strMovie.c_str()); @@ -514,7 +514,7 @@ int CIMDB::FindMovie(const CStdString &strMovie, IMDB_MOVIELIST& movieList, CGUI //CLog::Log(LOGDEBUG,"CIMDB::FindMovie(%s)", strMovie.c_str()); // load our scraper xml - if (!m_parser.Load(CUtil::AddFileToFolder("special://xbmc/system/scrapers/video/", m_info.strPath))) + if (!m_parser.Load(m_info)) return 0; m_parser.ClearCache(); @@ -561,7 +561,7 @@ bool CIMDB::GetDetails(const CScraperUrl &url, CVideoInfoTag &movieDetails, CGUI m_url = url; m_movieDetails = movieDetails; // load our scraper xml - if (!m_parser.Load("special://xbmc/system/scrapers/video/"+m_info.strPath)) + if (!m_parser.Load(m_info)) return false; // fill in the defaults @@ -631,7 +631,7 @@ bool CIMDB::GetEpisodeList(const CScraperUrl& url, IMDB_EPISODELIST& movieDetail m_episode = movieDetails; // load our scraper xml - if (!m_parser.Load(CUtil::AddFileToFolder("special://xbmc/system/scrapers/video/", m_info.strPath))) + if (!m_parser.Load(m_info)) return false; // fill in the defaults @@ -676,7 +676,7 @@ bool CIMDB::ScrapeFilename(const CStdString& strFileName, CVideoInfoTag& details CUtil::RemoveExtension(m_parser.m_param[0]); m_parser.m_param[0].Replace("_"," "); - CStdString strResult = m_parser.Parse("FileNameScrape",&m_info.settings); + CStdString strResult = m_parser.Parse("FileNameScrape"); CLog::Log(LOGDEBUG,"scraper: FileNameScrape returned %s", strResult.c_str()); TiXmlDocument doc; doc.Parse(strResult.c_str()); diff --git a/xbmc/utils/IMDB.h b/xbmc/utils/IMDB.h index bd1b71b4bb..ed9adb4dcb 100644 --- a/xbmc/utils/IMDB.h +++ b/xbmc/utils/IMDB.h @@ -33,7 +33,7 @@ #include "Thread.h" #include "ScraperParser.h" #include "VideoInfoTag.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "DateTime.h" #include "FileSystem/FileCurl.h" @@ -74,8 +74,8 @@ public: bool GetEpisodeList(const CScraperUrl& url, IMDB_EPISODELIST& details, CGUIDialogProgress *pProgress = NULL); bool ScrapeFilename(const CStdString& strFileName, CVideoInfoTag& details); - void SetScraperInfo(const SScraperInfo& info) { m_info.Reset(); m_info = info; } - const SScraperInfo& GetScraperInfo() const { return m_info; } + void SetScraperInfo(const ADDON::ScraperPtr& scraper) { m_info = scraper; } + const ADDON::ScraperPtr GetScraperInfo() const { return m_info; } static void ShowErrorDialog(const TiXmlElement* element); protected: @@ -102,7 +102,7 @@ protected: IMDB_EPISODELIST m_episode; LOOKUP_STATE m_state; int m_found; - SScraperInfo m_info; + ADDON::ScraperPtr m_info; }; #endif // !defined(AFX_IMDB1_H__562A722A_CD2A_4B4A_8A67_32DE8088A7D3__INCLUDED_) diff --git a/xbmc/utils/Makefile b/xbmc/utils/Makefile index d280a38773..034e23587b 100644 --- a/xbmc/utils/Makefile +++ b/xbmc/utils/Makefile @@ -1,10 +1,14 @@ INCLUDES=-I. -I.. -I../../ -I../linux -I../cores -I../../guilib -I../posix -I../../lib/jsoncpp/jsoncpp/include -SRCS=AlarmClock.cpp \ +SRCS=Addon.cpp \ + AddonManager.cpp \ + AlarmClock.cpp \ Archive.cpp \ Builtins.cpp \ CharsetConverter.cpp \ CriticalSection.cpp \ + DownloadQueue.cpp \ + DownloadQueueManager.cpp \ Event.cpp \ fstrcmp.cpp \ GUIInfoManager.cpp \ diff --git a/xbmc/utils/MusicAlbumInfo.cpp b/xbmc/utils/MusicAlbumInfo.cpp index fb1989d5b1..537afaa4f4 100644 --- a/xbmc/utils/MusicAlbumInfo.cpp +++ b/xbmc/utils/MusicAlbumInfo.cpp @@ -21,7 +21,7 @@ #include "MusicAlbumInfo.h" #include "ScraperParser.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "XMLUtils.h" #include "HTMLTable.h" #include "HTMLUtil.h" @@ -122,10 +122,10 @@ bool CMusicAlbumInfo::Parse(const TiXmlElement* album, bool bChained) } -bool CMusicAlbumInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, const CStdString& strFunction, const CScraperUrl* url) +bool CMusicAlbumInfo::Load(XFILE::CFileCurl& http, const ADDON::ScraperPtr& scraper, const CStdString& strFunction, const CScraperUrl* url) { // load our scraper xml - if (!m_parser.Load("special://xbmc/system/scrapers/music/" + info.strPath)) + if (!m_parser.Load(scraper)) return false; bool bChained=true; @@ -148,7 +148,7 @@ bool CMusicAlbumInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, con for (unsigned int i=0;i<strHTML.size();++i) m_parser.m_param[i] = strHTML[i]; - CStdString strXML = m_parser.Parse(strFunction,&info.settings); + CStdString strXML = m_parser.Parse(strFunction); CLog::Log(LOGDEBUG,"scraper: %s returned %s",strFunction.c_str(),strXML.c_str()); if (strXML.IsEmpty()) { @@ -179,7 +179,7 @@ bool CMusicAlbumInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, con if (szFunction) { CScraperUrl scrURL(xurl); - Load(http,info,szFunction,&scrURL); + Load(http,scraper,szFunction,&scrURL); } xurl = xurl->NextSiblingElement("url"); } diff --git a/xbmc/utils/MusicAlbumInfo.h b/xbmc/utils/MusicAlbumInfo.h index 0a57266bcf..bedcac9dda 100644 --- a/xbmc/utils/MusicAlbumInfo.h +++ b/xbmc/utils/MusicAlbumInfo.h @@ -23,11 +23,11 @@ #include "Song.h" #include "Album.h" +#include "Scraper.h" #include "ScraperParser.h" class TiXmlDocument; class CScraperUrl; -struct SScraperInfo; namespace XFILE { class CFileCurl; } @@ -53,7 +53,7 @@ public: float GetRelevance() const { return m_relevance; } void SetTitle(const CStdString& strTitle); void SetRelevance(float relevance) { m_relevance = relevance; } - bool Load(XFILE::CFileCurl& http, const SScraperInfo& info, const CStdString& strFunction="GetAlbumDetails", const CScraperUrl* url=NULL); + bool Load(XFILE::CFileCurl& http, const ADDON::ScraperPtr& scraper, const CStdString& strFunction="GetAlbumDetails", const CScraperUrl* url=NULL); bool Parse(const TiXmlElement* album, bool bChained=false); protected: CAlbum m_album; diff --git a/xbmc/utils/MusicArtistInfo.cpp b/xbmc/utils/MusicArtistInfo.cpp index d8ed90f3a3..d9711b58b7 100644 --- a/xbmc/utils/MusicArtistInfo.cpp +++ b/xbmc/utils/MusicArtistInfo.cpp @@ -21,7 +21,7 @@ #include "MusicArtistInfo.h" #include "ScraperParser.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "XMLUtils.h" #include "Settings.h" #include "CharsetConverter.h" @@ -77,10 +77,10 @@ bool CMusicArtistInfo::Parse(const TiXmlElement* artist, bool bChained) return true; } -bool CMusicArtistInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, const CStdString& strFunction, const CScraperUrl* url) +bool CMusicArtistInfo::Load(XFILE::CFileCurl& http, const ADDON::ScraperPtr& scraper, const CStdString& strFunction, const CScraperUrl* url) { // load our scraper xml - if (!m_parser.Load("special://xbmc/system/scrapers/music/" + info.strPath)) + if (!m_parser.Load(scraper)) return false; bool bChained=true; @@ -105,7 +105,7 @@ bool CMusicArtistInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, co m_parser.m_param[strHTML.size()] = m_strSearch; - CStdString strXML = m_parser.Parse(strFunction,&info.settings); + CStdString strXML = m_parser.Parse(strFunction); CLog::Log(LOGDEBUG,"scraper: %s returned %s",strFunction.c_str(),strXML.c_str()); if (strXML.IsEmpty()) { @@ -136,7 +136,7 @@ bool CMusicArtistInfo::Load(XFILE::CFileCurl& http, const SScraperInfo& info, co if (szFunction) { CScraperUrl scrURL(xurl); - Load(http,info,szFunction,&scrURL); + Load(http,scraper,szFunction,&scrURL); } xurl = xurl->NextSiblingElement("url"); } diff --git a/xbmc/utils/MusicArtistInfo.h b/xbmc/utils/MusicArtistInfo.h index 6bcfdbf38b..743ef26553 100644 --- a/xbmc/utils/MusicArtistInfo.h +++ b/xbmc/utils/MusicArtistInfo.h @@ -23,11 +23,11 @@ #include "Song.h" #include "Artist.h" +#include "Scraper.h" #include "ScraperParser.h" class TiXmlDocument; class CScraperUrl; -struct SScraperInfo; namespace MUSIC_GRABBER { @@ -43,7 +43,7 @@ public: const CArtist& GetArtist() const; CArtist& GetArtist(); const CScraperUrl& GetArtistURL() const; - bool Load(XFILE::CFileCurl& http, const SScraperInfo& info, const CStdString& strFunction="GetArtistDetails", const CScraperUrl* url=NULL); + bool Load(XFILE::CFileCurl& http, const ADDON::ScraperPtr& scraper, const CStdString& strFunction="GetArtistDetails", const CScraperUrl* url=NULL); bool Parse(const TiXmlElement* artist, bool bChained=false); CStdString m_strSearch; protected: diff --git a/xbmc/utils/MusicInfoScraper.cpp b/xbmc/utils/MusicInfoScraper.cpp index 019564cfe2..14a4ffb478 100644 --- a/xbmc/utils/MusicInfoScraper.cpp +++ b/xbmc/utils/MusicInfoScraper.cpp @@ -30,13 +30,15 @@ using namespace MUSIC_GRABBER; using namespace HTML; -CMusicInfoScraper::CMusicInfoScraper(const SScraperInfo& info) +using namespace ADDON; + +CMusicInfoScraper::CMusicInfoScraper(const ADDON::ScraperPtr &scraper) { m_bSuccessfull=false; m_bCanceled=false; m_iAlbum=-1; m_iArtist=-1; - m_info = info; + m_scraper = scraper; } CMusicInfoScraper::~CMusicInfoScraper(void) @@ -90,27 +92,19 @@ void CMusicInfoScraper::FindAlbuminfo() CScraperParser parser; parser.ClearCache(); - - if (!parser.Load("special://xbmc/system/scrapers/music/" + m_info.strPath) || !parser.HasFunction("CreateAlbumSearchUrl")) + if (!parser.Load(m_scraper) || !parser.HasFunction("CreateAlbumSearchUrl")) return; - if (!m_info.settings.GetPluginRoot() && m_info.settings.GetSettings().IsEmpty() && parser.HasFunction("GetSettings")) - { - m_info.settings.LoadSettingsXML("special://xbmc/system/scrapers/music/" + m_info.strPath); - m_info.settings.SaveFromDefault(); - } - parser.m_param[0] = strAlbum; parser.m_param[1] = m_strArtist; CUtil::URLEncode(parser.m_param[0]); CUtil::URLEncode(parser.m_param[1]); - CLog::Log(LOGDEBUG, "%s: Searching for '%s - %s' using %s scraper (file: '%s', content: '%s', language: '%s', date: '%s', framework: '%s')", - __FUNCTION__, m_strArtist.c_str(), strAlbum.c_str(), m_info.strTitle.c_str(), m_info.strPath.c_str(), m_info.strContent.c_str(), m_info.strLanguage.c_str(), m_info.strDate.c_str(), m_info.strFramework.c_str()); - + CLog::Log(LOGDEBUG, "%s: Searching for '%s - %s' using %s scraper (file: '%s', content: '%s')", + __FUNCTION__, m_strArtist.c_str(), strAlbum.c_str(), m_scraper->Name().c_str(), m_scraper->Path().c_str(), ADDON::TranslateContent(m_scraper->Content()).c_str()); CScraperUrl scrURL; - scrURL.ParseString(parser.Parse("CreateAlbumSearchUrl",&m_info.settings)); + scrURL.ParseString(parser.Parse("CreateAlbumSearchUrl")); if (!CScraperUrl::Get(scrURL.m_url[0], strHTML, m_http, parser.GetFilename()) || strHTML.size() == 0) { CLog::Log(LOGERROR, "%s: Unable to retrieve web site",__FUNCTION__); @@ -118,7 +112,7 @@ void CMusicInfoScraper::FindAlbuminfo() } parser.m_param[0] = strHTML; - CStdString strXML = parser.Parse("GetAlbumSearchResults",&m_info.settings); + CStdString strXML = parser.Parse("GetAlbumSearchResults"); CLog::Log(LOGDEBUG,"scraper: GetAlbumSearchResults returns %s",strXML.c_str()); if (strXML.IsEmpty()) { @@ -203,24 +197,23 @@ void CMusicInfoScraper::FindArtistinfo() CScraperParser parser; parser.ClearCache(); - - if (!parser.Load("special://xbmc/system/scrapers/music/" + m_info.strPath) || !parser.HasFunction("CreateArtistSearchUrl")) + if (!parser.Load(m_scraper) || !parser.HasFunction("CreateAlbumSearchUrl")) return; - if (!m_info.settings.GetPluginRoot() && m_info.settings.GetSettings().IsEmpty() && parser.HasFunction("GetSettings")) + if (!m_scraper->GetSettingsXML() && parser.HasFunction("GetSettings")) { - m_info.settings.LoadSettingsXML("special://xbmc/system/scrapers/music/" + m_info.strPath); - m_info.settings.SaveFromDefault(); + m_scraper->LoadSettings(); + m_scraper->SaveFromDefault(); } parser.m_param[0] = m_strArtist; CUtil::URLEncode(parser.m_param[0]); - CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper (file: '%s', content: '%s', language: '%s', date: '%s', framework: '%s')", - __FUNCTION__, m_strArtist.c_str(), m_info.strTitle.c_str(), m_info.strPath.c_str(), m_info.strContent.c_str(), m_info.strLanguage.c_str(), m_info.strDate.c_str(), m_info.strFramework.c_str()); + CLog::Log(LOGDEBUG, "%s: Searching for '%s' using %s scraper (file: '%s', content: '%s')", + __FUNCTION__, m_strArtist.c_str(), m_scraper->Name().c_str(), m_scraper->Path().c_str(), ADDON::TranslateContent(m_scraper->Content()).c_str()); CScraperUrl scrURL; - scrURL.ParseString(parser.Parse("CreateArtistSearchUrl",&m_info.settings)); + scrURL.ParseString(parser.Parse("CreateArtistSearchUrl")); if (!CScraperUrl::Get(scrURL.m_url[0], strHTML, m_http, parser.GetFilename()) || strHTML.size() == 0) { CLog::Log(LOGERROR, "%s: Unable to retrieve web site",__FUNCTION__); @@ -228,7 +221,7 @@ void CMusicInfoScraper::FindArtistinfo() } parser.m_param[0] = strHTML; - CStdString strXML = parser.Parse("GetArtistSearchResults",&m_info.settings); + CStdString strXML = parser.Parse("GetArtistSearchResults"); CLog::Log(LOGDEBUG,"scraper: GetArtistSearchResults returns %s",strXML.c_str()); if (strXML.IsEmpty()) { @@ -309,7 +302,7 @@ void CMusicInfoScraper::LoadAlbuminfo() CMusicAlbumInfo& album=m_vecAlbums[m_iAlbum]; album.GetAlbum().strArtist.Empty(); - if (album.Load(m_http,m_info)) + if (album.Load(m_http,m_scraper)) m_bSuccessfull=true; } @@ -320,7 +313,7 @@ void CMusicInfoScraper::LoadArtistinfo() CMusicArtistInfo& artist=m_vecArtists[m_iArtist]; artist.GetArtist().strArtist.Empty(); - if (artist.Load(m_http,m_info)) + if (artist.Load(m_http,m_scraper)) m_bSuccessfull=true; } @@ -387,9 +380,13 @@ void CMusicInfoScraper::Process() bool CMusicInfoScraper::CheckValidOrFallback(const CStdString &fallbackScraper) { CScraperParser parser; - if (parser.Load("special://xbmc/system/scrapers/music/" + m_info.strPath)) + if (parser.Load(m_scraper)) return true; - if (m_info.strPath != fallbackScraper && + else + return false; +/* + * TODO handle fallback mechanism + if (m_scraper->Path() != fallbackScraper && parser.Load("special://xbmc/system/scrapers/music/" + fallbackScraper)) { CLog::Log(LOGWARNING, "%s - scraper %s fails to load, falling back to %s", __FUNCTION__, m_info.strPath.c_str(), fallbackScraper.c_str()); @@ -402,5 +399,5 @@ bool CMusicInfoScraper::CheckValidOrFallback(const CStdString &fallbackScraper) m_info.settings.LoadSettingsXML("special://xbmc/system/scrapers/music/" + m_info.strPath); return true; } - return false; + return false; */ } diff --git a/xbmc/utils/MusicInfoScraper.h b/xbmc/utils/MusicInfoScraper.h index 2c8cfe2466..729fec7d3a 100644 --- a/xbmc/utils/MusicInfoScraper.h +++ b/xbmc/utils/MusicInfoScraper.h @@ -23,7 +23,7 @@ #include "MusicAlbumInfo.h" #include "MusicArtistInfo.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "Thread.h" #include "FileSystem/FileCurl.h" @@ -34,7 +34,7 @@ namespace MUSIC_GRABBER class CMusicInfoScraper : public CThread { public: - CMusicInfoScraper(const SScraperInfo& info); + CMusicInfoScraper(const ADDON::ScraperPtr &scraper); virtual ~CMusicInfoScraper(void); void FindAlbuminfo(const CStdString& strAlbum, const CStdString& strArtist = ""); void LoadAlbuminfo(int iAlbum); @@ -56,9 +56,9 @@ public: { return m_vecAlbums; } - void SetScraperInfo(const SScraperInfo& info) + void SetScraperInfo(const ADDON::ScraperPtr& scraper) { - m_info = info; + m_scraper = scraper; } /*! \brief Checks whether we have a valid scraper. If not, we try the fallbackScraper @@ -84,7 +84,7 @@ protected: bool m_bSuccessfull; bool m_bCanceled; XFILE::CFileCurl m_http; - SScraperInfo m_info; + ADDON::ScraperPtr m_scraper; }; } diff --git a/xbmc/utils/ScraperParser.cpp b/xbmc/utils/ScraperParser.cpp index bc1b372458..a623d5738c 100644 --- a/xbmc/utils/ScraperParser.cpp +++ b/xbmc/utils/ScraperParser.cpp @@ -25,12 +25,14 @@ #include "system.h" #endif +#include "AddonManager.h" #include "RegExp.h" #include "HTMLUtil.h" -#include "ScraperSettings.h" +#include "Scraper.h" #include "FileSystem/File.h" #include "FileSystem/Directory.h" #include "Util.h" +#include "StringUtils.h" #include "AdvancedSettings.h" #include "FileItem.h" @@ -38,18 +40,13 @@ #include <cstring> using namespace std; +using namespace ADDON; using namespace XFILE; CScraperParser::CScraperParser() { m_pRootElement = NULL; - m_name = m_content = NULL; - m_thumb = NULL; m_document = NULL; - m_settings = NULL; - m_language = NULL; - m_framework = NULL; - m_date = NULL; m_requiressettings = false; m_SearchStringEncoding = "UTF-8"; } @@ -68,7 +65,7 @@ CScraperParser &CScraperParser::operator=(const CScraperParser &parser) Clear(); if (parser.m_document) { - m_strFile = parser.m_strFile; + m_scraper = parser.m_scraper; m_persistence = parser.m_persistence; m_document = new TiXmlDocument(*parser.m_document); LoadFromXML(); @@ -88,93 +85,107 @@ void CScraperParser::Clear() delete m_document; m_document = NULL; - m_name = m_thumb = m_content = m_language = m_framework = m_date = NULL; m_requiressettings = false; - m_settings = NULL; m_strFile.Empty(); } bool CScraperParser::Load(const CStdString& strXMLFile) { - Clear(); + //TODO drop loading by UUID support, then remove AddonMgr include + if (StringUtils::ValidateUUID(strXMLFile)) + { + AddonPtr scraper; + if (!CAddonMgr::Get()->GetAddon(ADDON_SCRAPER, strXMLFile, scraper)) + return false; + else + return Load(scraper); + } + else + { + Clear(); + + m_document = new TiXmlDocument(strXMLFile); + + if (!m_document) + return false; - m_document = new TiXmlDocument(strXMLFile); + m_strFile = strXMLFile; - if (!m_document) + if (m_document->LoadFile()) + return LoadFromXML(); + + delete m_document; + m_document = NULL; return false; + } +} - m_strFile = strXMLFile; +bool CScraperParser::Load(const AddonPtr& scraper) +{ + if (!scraper) + return false; - if (m_document->LoadFile()) - return LoadFromXML(); + m_scraper = scraper; - delete m_document; - m_document = NULL; - return false; + return Load(m_scraper->Path() + m_scraper->LibName()); } bool CScraperParser::LoadFromXML() { - if (!m_document) + if (!m_document || !m_scraper) return false; - CStdString strPath; - CUtil::GetDirectory(m_strFile,strPath); + CStdString strPath = m_scraper->Path(); m_pRootElement = m_document->RootElement(); CStdString strValue = m_pRootElement->Value(); if (strValue == "scraper") { - m_name = m_pRootElement->Attribute("name"); - m_thumb = m_pRootElement->Attribute("thumb"); - m_content = m_pRootElement->Attribute("content"); - m_language = m_pRootElement->Attribute("language"); - m_framework = m_pRootElement->Attribute("framework"); - m_date = m_pRootElement->Attribute("date"); + CONTENT_TYPE content = TranslateContent(m_pRootElement->Attribute("content")); if (m_pRootElement->Attribute("cachePersistence")) m_persistence.SetFromTimeString(m_pRootElement->Attribute("cachePersistence")); const char* requiressettings; m_requiressettings = ((requiressettings = m_pRootElement->Attribute("requiressettings")) && strnicmp("true", requiressettings, 4) == 0); - if (m_name && m_content) // FIXME + // check for known content + if ( content == CONTENT_TVSHOWS || + content == CONTENT_MOVIES || + content == CONTENT_MUSICVIDEOS || + content == CONTENT_ALBUMS) { - // check for known content - if ((0 == stricmp(m_content,"tvshows")) || - (0 == stricmp(m_content,"movies")) || - (0 == stricmp(m_content,"musicvideos")) || - (0 == stricmp(m_content,"albums"))) + TiXmlElement* pChildElement = m_pRootElement->FirstChildElement("CreateSearchUrl"); + if (pChildElement) { - TiXmlElement* pChildElement = m_pRootElement->FirstChildElement("CreateSearchUrl"); - if (pChildElement) + if (!(m_SearchStringEncoding = pChildElement->Attribute("SearchStringEncoding"))) + m_SearchStringEncoding = "UTF-8"; + } + + ADDONDEPS deps = m_scraper->GetDeps(); + ADDONDEPS::iterator itr = deps.begin(); + while (itr != deps.end()) + { + AddonPtr dep; + if (!CAddonMgr::Get()->GetAddon(ADDON_SCRAPER_LIBRARY, (*itr).first, dep)) { - if (!(m_SearchStringEncoding = pChildElement->Attribute("SearchStringEncoding"))) - m_SearchStringEncoding = "UTF-8"; + itr++; + continue; } - - // inject includes - const TiXmlElement* include = m_pRootElement->FirstChildElement("include"); - while (include) + CStdString strFile = CUtil::AddFileToFolder(dep->Path(), dep->LibName()); + TiXmlDocument doc; + if (doc.LoadFile(strFile)) { - if (include->FirstChild()) + const TiXmlNode* node = doc.RootElement()->FirstChild(); + while (node) { - CStdString strFile = CUtil::AddFileToFolder(strPath,include->FirstChild()->Value()); - TiXmlDocument doc; - if (doc.LoadFile(strFile)) - { - const TiXmlNode* node = doc.RootElement()->FirstChild(); - while (node) - { - m_pRootElement->InsertEndChild(*node); - node = node->NextSibling(); - } - } + m_pRootElement->InsertEndChild(*node); + node = node->NextSibling(); } - include = include->NextSiblingElement("include"); } - - return true; + itr++; } + + return true; } } delete m_document; @@ -200,11 +211,11 @@ void CScraperParser::ReplaceBuffers(CStdString& strDest) } // insert settings iIndex = 0; - while ((size_t)(iIndex = strDest.find("$INFO[",iIndex)) != CStdString::npos && m_settings) + while ((size_t)(iIndex = strDest.find("$INFO[",iIndex)) != CStdString::npos) { int iEnd = strDest.Find("]",iIndex); CStdString strInfo = strDest.Mid(iIndex+6,iEnd-iIndex-6); - CStdString strReplace = m_settings->Get(strInfo); + CStdString strReplace = m_scraper->GetSetting(strInfo); strDest.replace(strDest.begin()+iIndex,strDest.begin()+iEnd+1,strReplace); iIndex += strReplace.length(); } @@ -396,8 +407,8 @@ void CScraperParser::ParseNext(TiXmlElement* element) szConditional++; } CStdString strSetting; - if (m_settings) - strSetting = m_settings->Get(szConditional); + if (m_scraper && m_scraper->HasSettings()) + strSetting = m_scraper->GetSetting(szConditional); bExecute = bInverse != strSetting.Equals("true"); } @@ -408,14 +419,13 @@ void CScraperParser::ParseNext(TiXmlElement* element) } } -const CStdString CScraperParser::Parse(const CStdString& strTag, const CScraperSettings* pSettings) +const CStdString CScraperParser::Parse(const CStdString& strTag) { TiXmlElement* pChildElement = m_pRootElement->FirstChildElement(strTag.c_str()); if(pChildElement == NULL) return ""; int iResult = 1; // default to param 1 pChildElement->QueryIntAttribute("dest",&iResult); TiXmlElement* pChildStart = pChildElement->FirstChildElement("RegExp"); - m_settings = pSettings; ParseNext(pChildStart); CStdString tmp = m_param[iResult-1]; diff --git a/xbmc/utils/ScraperParser.h b/xbmc/utils/ScraperParser.h index 63fc8572ff..7944a89f63 100644 --- a/xbmc/utils/ScraperParser.h +++ b/xbmc/utils/ScraperParser.h @@ -24,6 +24,7 @@ #include <vector> #include "StdString.h" +#include "IAddon.h" #include "DateTime.h" #define MAX_SCRAPER_BUFFERS 20 @@ -43,15 +44,10 @@ public: void Clear(); bool Load(const CStdString& strXMLFile); - const CStdString GetName() { return m_name; } - const CStdString GetThumb() { return m_thumb; } - const CStdString GetContent() { return m_content; } - const CStdString GetLanguage() { return m_language; } - const CStdString GetFramework() { return m_framework; } - const CStdString GetDate() { return m_date; } + bool Load(const ADDON::AddonPtr& scraper); const CStdString GetFilename() { return m_strFile; } const CStdString GetSearchStringEncoding() { return m_SearchStringEncoding; } - const CStdString Parse(const CStdString& strTag, const CScraperSettings* pSettings=NULL); + const CStdString Parse(const CStdString& strTag); bool HasFunction(const CStdString& strTag); bool RequiresSettings() { return m_requiressettings; } @@ -69,22 +65,15 @@ private: void GetBufferParams(bool* result, const char* attribute, bool defvalue); void InsertToken(CStdString& strOutput, int buf, const char* token); + ADDON::AddonPtr m_scraper; TiXmlDocument* m_document; TiXmlElement* m_pRootElement; - const char* m_name; - const char* m_thumb; - const char* m_content; - const char* m_language; - const char* m_framework; - const char* m_date; const char* m_SearchStringEncoding; CDateTimeSpan m_persistence; bool m_requiressettings; CStdString m_strFile; - - const CScraperSettings* m_settings; }; #endif diff --git a/xbmc/utils/ScraperUrl.cpp b/xbmc/utils/ScraperUrl.cpp index afea059ff4..22a31356b3 100644 --- a/xbmc/utils/ScraperUrl.cpp +++ b/xbmc/utils/ScraperUrl.cpp @@ -174,7 +174,7 @@ const CScraperUrl::SUrlEntry CScraperUrl::GetSeasonThumb(int season) const return result; } -bool CScraperUrl::Get(const SUrlEntry& scrURL, string& strHTML, XFILE::CFileCurl& http, const CStdString& cacheContext1) +bool CScraperUrl::Get(const SUrlEntry& scrURL, std::string& strHTML, XFILE::CFileCurl& http, const CStdString& cacheContext1) { CURL url(scrURL.m_url); http.SetReferer(scrURL.m_spoof); diff --git a/xbmc/visualizations/DirectXSpectrum/directx_spectrum.cpp b/xbmc/visualizations/DirectXSpectrum/directx_spectrum.cpp index 1214bf0ade..dcff0baa3a 100644 --- a/xbmc/visualizations/DirectXSpectrum/directx_spectrum.cpp +++ b/xbmc/visualizations/DirectXSpectrum/directx_spectrum.cpp @@ -28,7 +28,7 @@ */
-#include "../../../visualisations/xbmc_vis.h"
+#include "../../addons/include/xbmc_vis_dll.h"
#include <math.h>
#include <D3D9.h>
#include <d3dx9math.h>
@@ -51,38 +51,6 @@ typedef struct #define VERTEX_FORMAT (D3DFVF_XYZ | D3DFVF_DIFFUSE)
-vector<VisSetting> g_vecSettings;
-
-extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth, int iHeight, const char* szVisualisationName,
- float fPixelRatio, const char *szSubModuleName)
-{
- g_device = (LPDIRECT3DDEVICE9)pd3dDevice;
-
- g_vecSettings.clear();
- m_uiVisElements = 0;
- VisSetting scale(VisSetting::SPIN, "Bar Height");
- scale.AddEntry("Default");
- scale.AddEntry("Big");
- scale.AddEntry("Very Big");
- scale.AddEntry("Small");
-
- VisSetting mode(VisSetting::SPIN, "Mode");
- mode.AddEntry("Default");
- mode.AddEntry("Wireframe");
- mode.AddEntry("Points");
-
- VisSetting speed(VisSetting::SPIN, "Speed");
- speed.AddEntry("Default");
- speed.AddEntry("Slow");
- speed.AddEntry("Very Slow");
- speed.AddEntry("Fast");
- speed.AddEntry("Very Fast");
-
- g_vecSettings.push_back( scale );
- g_vecSettings.push_back( mode );
- g_vecSettings.push_back( speed );
-}
-
void draw_vertex(Vertex_t * pVertex, float x, float y, float z, D3DCOLOR color) {
pVertex->col = color;
pVertex->x = x;
@@ -188,6 +156,21 @@ void draw_bars(void) }
}
+//-- Create -------------------------------------------------------------------
+// Called on load. Addon should fully initalize or return error status
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+ADDON_STATUS Create(void* hdl, void* visProps)
+{
+ if (!visProps)
+ return STATUS_UNKNOWN;
+
+ VIS_PROPS* props = (VIS_PROPS*) visProps;
+ g_device = (LPDIRECT3DDEVICE9) props->device;
+
+ return STATUS_NEED_SETTINGS;
+}
+
//-- Render -------------------------------------------------------------------
// Called once per frame. Do all rendering here.
//-----------------------------------------------------------------------------
@@ -261,7 +244,7 @@ extern "C" void Stop() }
-extern "C" void AudioData(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
+extern "C" void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
{
int i,c;
int y=0;
@@ -308,11 +291,18 @@ extern "C" void GetInfo(VIS_INFO* pInfo) pInfo->iSyncDelay = 0;
}
+//-- GetSubModules ------------------------------------------------------------
+// Return any sub modules supported by this vis
+//-----------------------------------------------------------------------------
+extern "C" unsigned int GetSubModules(char ***names)
+{
+ return 0; // this vis supports 0 sub modules
+}
//-- OnAction -----------------------------------------------------------------
// Handle XBMC actions such as next preset, lock preset, album art changed etc
//-----------------------------------------------------------------------------
-extern "C" bool OnAction(long flags, void *param)
+extern "C" bool OnAction(long flags, const void *param)
{
bool ret = false;
return ret;
@@ -321,39 +311,83 @@ extern "C" bool OnAction(long flags, void *param) //-- GetPresets ---------------------------------------------------------------
// Return a list of presets to XBMC for display
//-----------------------------------------------------------------------------
-extern "C" void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked)
+extern "C" unsigned int GetPresets(char ***presets)
+{
+ return 0;
+}
+
+//-- GetPreset ----------------------------------------------------------------
+// Return the index of the current playing preset
+//-----------------------------------------------------------------------------
+extern "C" unsigned GetPreset()
+{
+ return 0;
+}
+
+//-- IsLocked -----------------------------------------------------------------
+// Returns true if this add-on use settings
+//-----------------------------------------------------------------------------
+extern "C" bool IsLocked()
+{
+ return false;
+}
+
+//-- Remove -------------------------------------------------------------------
+// Do everything before unload of this add-on
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" void Remove()
{
+}
+
+//-- HasSettings --------------------------------------------------------------
+// Returns true if this add-on use settings
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" bool HasSettings()
+{
+ return true;
+}
+//-- GetStatus ---------------------------------------------------------------
+// Returns the current Status of this visualisation
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" ADDON_STATUS GetStatus()
+{
+ return STATUS_OK;
}
//-- GetSettings --------------------------------------------------------------
// Return the settings for XBMC to display
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" unsigned int GetSettings(StructSetting*** sSet)
-{
- m_uiVisElements = VisUtils::VecToStruct(g_vecSettings, &m_structSettings);
- *sSet = m_structSettings;
- return m_uiVisElements;
+extern "C" unsigned int GetSettings(StructSetting ***sSet)
+{
+ return 0;
}
+//-- FreeSettings --------------------------------------------------------------
+// Free the settings struct passed from XBMC
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+
extern "C" void FreeSettings()
{
- VisUtils::FreeStruct(m_uiVisElements, &m_structSettings);
}
-//-- UpdateSetting ------------------------------------------------------------
-// Handle setting change request from XBMC
+//-- SetSetting ---------------------------------------------------------------
+// Set a specific Setting value (called from XBMC)
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" void UpdateSetting(int num, StructSetting*** sSet)
+extern "C" ADDON_STATUS SetSetting(const char *strSetting, const void* value)
{
- VisUtils::StructToVec(m_uiVisElements, sSet, &g_vecSettings);
-
- if ( (int)g_vecSettings.size() <= num || num < 0 )
- return;
+ if (!strSetting || !value)
+ return STATUS_UNKNOWN;
- if (strcmp(g_vecSettings[num].name, "Size")==0)
+ if (strcmp(strSetting, "size")==0)
{
- switch (g_vecSettings[num].current)
+ switch (*(int*) value)
{
case 0:
scale = 1.0f / log(256.0f);
@@ -375,11 +409,12 @@ extern "C" void UpdateSetting(int num, StructSetting*** sSet) scale = 0.33f / log(256.0f);
break;
}
+ return STATUS_OK;
}
- if (strcmp(g_vecSettings[num].name, "Speed")==0)
+ else if (strcmp(strSetting, "speed")==0)
{
- switch (g_vecSettings[num].current)
+ switch (*(int*) value)
{
case 0:
hSpeed = 0.05f;
@@ -401,11 +436,12 @@ extern "C" void UpdateSetting(int num, StructSetting*** sSet) hSpeed = 0.20f;
break;
}
+ return STATUS_OK;
}
- if (strcmp(g_vecSettings[num].name, "Mode")==0)
+ else if (strcmp(strSetting, "mode")==0)
{
- switch (g_vecSettings[num].current)
+ switch (*(int*) value)
{
case 0:
g_mode = D3DFILL_SOLID;
@@ -419,13 +455,8 @@ extern "C" void UpdateSetting(int num, StructSetting*** sSet) g_mode = D3DFILL_POINT;
break;
}
+ return STATUS_OK;
}
+ return STATUS_UNKNOWN;
}
-//-- GetSubModules ------------------------------------------------------------
-// Return any sub modules supported by this vis
-//-----------------------------------------------------------------------------
-extern "C" int GetSubModules(char ***names, char ***paths)
-{
- return 0; // this vis supports 0 sub modules
-}
\ No newline at end of file diff --git a/xbmc/visualizations/DllVisualisation.h b/xbmc/visualizations/DllVisualisation.h index bc87588658..f5e9fb083f 100644 --- a/xbmc/visualizations/DllVisualisation.h +++ b/xbmc/visualizations/DllVisualisation.h @@ -19,20 +19,11 @@ * http://www.gnu.org/copyleft/gpl.html * */ -#include "DynamicDll.h" -#include "visualizations/VisualisationTypes.h" -class DllVisualisationInterface -{ -public: - void GetModule(struct Visualisation* pScr); -}; +#include "../DllAddon.h" +#include "../addons/include/xbmc_vis_types.h" -class DllVisualisation : public DllDynamic, DllVisualisationInterface +class DllVisualisation : public DllAddon<Visualisation, VIS_PROPS> { - DECLARE_DLL_WRAPPER_TEMPLATE(DllVisualisation) - DEFINE_METHOD1(void, GetModule, (struct Visualisation* p1)) - BEGIN_METHOD_RESOLVE() - RESOLVE_METHOD_RENAME(get_module,GetModule) - END_METHOD_RESOLVE() + // this is populated via Macro calls in DllAddon.h }; diff --git a/xbmc/visualizations/Makefile b/xbmc/visualizations/Makefile index 0b3a537b5e..7768d61c4b 100644 --- a/xbmc/visualizations/Makefile +++ b/xbmc/visualizations/Makefile @@ -1,8 +1,9 @@ -INCLUDES=-I. -I../ -I../linux -I../../guilib -I../utils +INCLUDES=-I. -I../ -I../linux -I../../guilib -I../utils -I../addons/include -SRCS=fft.cpp Visualisation.cpp VisualisationFactory.cpp +SRCS=fft.cpp Visualisation.cpp LIB=visualization.a +SLIB=../lib/libvisualisation/libvisualisation.a include ../../Makefile.include -include $(OBJS:.o=.P) diff --git a/xbmc/visualizations/OpenGLSpectrum/Makefile.in b/xbmc/visualizations/OpenGLSpectrum/Makefile.in index 29dec4e9bd..b8e93c718d 100644 --- a/xbmc/visualizations/OpenGLSpectrum/Makefile.in +++ b/xbmc/visualizations/OpenGLSpectrum/Makefile.in @@ -1,10 +1,10 @@ ARCH=@ARCH@ -INCLUDES=-I. -I.. -I../../linux -I../../ -I ../../../guilib +INCLUDES=-I. -I.. -I../../linux -I../../addons/include -I../../ -I ../../../guilib DEFINES+=-DHAS_SDL_OPENGL -DHAS_SDL CXXFLAGS=-fPIC OBJS=opengl_spectrum.o -SLIB=../../../visualisations/opengl_spectrum.vis +SLIB=../../../addons/visualizations/GLSpectrum/opengl_spectrum.vis $(SLIB): $(OBJS) ifeq ($(findstring osx,$(ARCH)), osx) diff --git a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp index 96a185c12d..ee31d92b25 100644 --- a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp +++ b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.cpp @@ -28,7 +28,8 @@ */ -#include "../../../visualisations/xbmc_vis.h" +#include "../../addons/include/xbmc_vis_dll.h" +#include <string.h> #include <math.h> #include <GL/glew.h> @@ -40,35 +41,6 @@ GLfloat z_angle = 0.0, z_speed = 0.0; GLfloat heights[16][16], cHeights[16][16], scale; GLfloat hSpeed = 0.05; GLenum g_mode = GL_FILL; -vector<VisSetting> g_vecSettings; - -extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth, int iHeight, const char* szVisualisationName, - float fPixelRatio, const char *szSubModuleName) -{ - g_vecSettings.clear(); - m_uiVisElements = 0; - VisSetting scale(VisSetting::SPIN, "Bar Height"); - scale.AddEntry("Default"); - scale.AddEntry("Big"); - scale.AddEntry("Very Big"); - scale.AddEntry("Small"); - - VisSetting mode(VisSetting::SPIN, "Mode"); - mode.AddEntry("Default"); - mode.AddEntry("Wireframe"); - mode.AddEntry("Points"); - - VisSetting speed(VisSetting::SPIN, "Speed"); - speed.AddEntry("Default"); - speed.AddEntry("Slow"); - speed.AddEntry("Very Slow"); - speed.AddEntry("Fast"); - speed.AddEntry("Very Fast"); - - g_vecSettings.push_back( scale ); - g_vecSettings.push_back( mode ); - g_vecSettings.push_back( speed ); -} void draw_rectangle(GLfloat x1, GLfloat y1, GLfloat z1, GLfloat x2, GLfloat y2, GLfloat z2) { @@ -155,8 +127,8 @@ void draw_bars(void) cHeights[y][x] -= hSpeed; } draw_bar(x_offset, z_offset, - cHeights[y][x], r_base - (x * (r_base / 15.0)), - x * (1.0 / 15), b_base); + cHeights[y][x], r_base - (x * (r_base / 15.0)), + x * (1.0 / 15), b_base); } } glEnd(); @@ -164,13 +136,22 @@ void draw_bars(void) glPopMatrix(); } +//-- Create ------------------------------------------------------------------- +// Called on load. Addon should fully initalize or return error status +//----------------------------------------------------------------------------- +ADDON_STATUS Create(void* hdl, void* props) +{ + if (!props) + return STATUS_UNKNOWN; + + return STATUS_NEED_SETTINGS; +} + //-- Render ------------------------------------------------------------------- // Called once per frame. Do all rendering here. //----------------------------------------------------------------------------- extern "C" void Render() { - bool configured = true; //FALSE; - glDisable(GL_BLEND); glMatrixMode(GL_PROJECTION); glPushMatrix(); @@ -183,22 +164,19 @@ extern "C" void Render() glDepthFunc(GL_LESS); glPolygonMode(GL_FRONT, GL_FILL); //glPolygonMode(GL_BACK, GL_FILL); - if(configured) - { - x_angle += x_speed; - if(x_angle >= 360.0) - x_angle -= 360.0; + x_angle += x_speed; + if(x_angle >= 360.0) + x_angle -= 360.0; - y_angle += y_speed; - if(y_angle >= 360.0) - y_angle -= 360.0; + y_angle += y_speed; + if(y_angle >= 360.0) + y_angle -= 360.0; - z_angle += z_speed; - if(z_angle >= 360.0) - z_angle -= 360.0; + z_angle += z_speed; + if(z_angle >= 360.0) + z_angle -= 360.0; - draw_bars(); - } + draw_bars(); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -233,7 +211,7 @@ extern "C" void Stop() } -extern "C" void AudioData(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength) +extern "C" void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength) { int i,c; int y=0; @@ -281,10 +259,18 @@ extern "C" void GetInfo(VIS_INFO* pInfo) } +//-- GetSubModules ------------------------------------------------------------ +// Return any sub modules supported by this vis +//----------------------------------------------------------------------------- +extern "C" unsigned int GetSubModules(char ***names) +{ + return 0; // this vis supports 0 sub modules +} + //-- OnAction ----------------------------------------------------------------- // Handle XBMC actions such as next preset, lock preset, album art changed etc //----------------------------------------------------------------------------- -extern "C" bool OnAction(long flags, void *param) +extern "C" bool OnAction(long flags, const void *param) { bool ret = false; return ret; @@ -293,111 +279,154 @@ extern "C" bool OnAction(long flags, void *param) //-- GetPresets --------------------------------------------------------------- // Return a list of presets to XBMC for display //----------------------------------------------------------------------------- -extern "C" void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked) +extern "C" unsigned int GetPresets(char ***presets) { + return 0; +} + +//-- GetPreset ---------------------------------------------------------------- +// Return the index of the current playing preset +//----------------------------------------------------------------------------- +extern "C" unsigned GetPreset() +{ + return 0; +} + +//-- IsLocked ----------------------------------------------------------------- +// Returns true if this add-on use settings +//----------------------------------------------------------------------------- +extern "C" bool IsLocked() +{ + return false; +} +//-- Remove ------------------------------------------------------------------- +// Do everything before unload of this add-on +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" void Remove() +{ +} + +//-- HasSettings -------------------------------------------------------------- +// Returns true if this add-on use settings +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" bool HasSettings() +{ + return true; +} + +//-- GetStatus --------------------------------------------------------------- +// Returns the current Status of this visualisation +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" ADDON_STATUS GetStatus() +{ + return STATUS_OK; } //-- GetSettings -------------------------------------------------------------- // Return the settings for XBMC to display +// !!! Add-on master function !!! //----------------------------------------------------------------------------- -extern "C" unsigned int GetSettings(StructSetting*** sSet) -{ - m_uiVisElements = VisUtils::VecToStruct(g_vecSettings, &m_structSettings); - *sSet = m_structSettings; - return m_uiVisElements; +extern "C" unsigned int GetSettings(StructSetting ***sSet) +{ + return 0; } +//-- FreeSettings -------------------------------------------------------------- +// Free the settings struct passed from XBMC +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- + extern "C" void FreeSettings() { - VisUtils::FreeStruct(m_uiVisElements, &m_structSettings); } -//-- UpdateSetting ------------------------------------------------------------ -// Handle setting change request from XBMC +//-- SetSetting --------------------------------------------------------------- +// Set a specific Setting value (called from XBMC) +// !!! Add-on master function !!! //----------------------------------------------------------------------------- -extern "C" void UpdateSetting(int num, StructSetting*** sSet) +extern "C" ADDON_STATUS SetSetting(const char *strSetting, const void* value) { - VisUtils::StructToVec(m_uiVisElements, sSet, &g_vecSettings); - - if ( (int)g_vecSettings.size() <= num || num < 0 ) - return; + if (!strSetting || !value) + return STATUS_UNKNOWN; - if (strcmp(g_vecSettings[num].name, "Size")==0) + if (strcmp(strSetting, "mode")==0) { - switch (g_vecSettings[num].current) + switch (*(int*) value) + { + case 1: + g_mode = GL_LINE; + break; + + case 2: + g_mode = GL_POINT; + break; + + case 0: + default: + g_mode = GL_FILL; + break; + } + return STATUS_OK; + } + else if (strcmp(strSetting, "size")==0) + { + switch (*(int*) value) { - case 0: - scale = 1.0 / log(256.0); - break; - case 1: - scale = 2.0 / log(256.0); + scale = 2.f / log(256.f); break; case 2: - scale = 3.0 / log(256.0); + scale = 3.f / log(256.f); break; case 3: - scale = 0.5 / log(256.0); + scale = 0.5f / log(256.f); break; case 4: - scale = 0.33 / log(256.0); + scale = 0.33f / log(256.f); + break; + + case 0: + default: + scale = 1.f / log(256.f); break; } + return STATUS_OK; } - - if (strcmp(g_vecSettings[num].name, "Speed")==0) + else if (strcmp(strSetting, "speed")==0) { - switch (g_vecSettings[num].current) + switch (*(int*) value) { - case 0: - hSpeed = 0.05; - break; - case 1: - hSpeed = 0.025; + hSpeed = 0.025f; break; case 2: - hSpeed = 0.0125; + hSpeed = 0.0125f; break; case 3: - hSpeed = 0.10; + hSpeed = 0.1f; break; case 4: - hSpeed = 0.20; + hSpeed = 0.2f; break; - } - } - if (strcmp(g_vecSettings[num].name, "Mode")==0) - { - switch (g_vecSettings[num].current) - { case 0: - g_mode = GL_FILL; - break; - - case 1: - g_mode = GL_LINE; - break; - - case 2: - g_mode = GL_POINT; + default: + hSpeed = 0.05f; break; } + return STATUS_OK; } -} -//-- GetSubModules ------------------------------------------------------------ -// Return any sub modules supported by this vis -//----------------------------------------------------------------------------- -extern "C" int GetSubModules(char ***names, char ***paths) -{ - return 0; // this vis supports 0 sub modules + return STATUS_UNKNOWN; } + diff --git a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.vcproj b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.vcproj index d2325d6469..b304b54a52 100644 --- a/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.vcproj +++ b/xbmc/visualizations/OpenGLSpectrum/opengl_spectrum.vcproj @@ -1,142 +1,211 @@ -<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
- ProjectType="Visual C++"
- Version="7.10"
- Name="opengl_spectrum"
- ProjectGUID="{0D91724A-E6F6-4708-AF47-9F88BBE2114B}"
- Keyword="Win32Proj">
- <Platforms>
- <Platform
- Name="Win32"/>
- </Platforms>
- <Configurations>
- <Configuration
- Name="Debug|Win32"
- OutputDirectory="Debug"
- IntermediateDirectory="Debug"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- Optimization="0"
- PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OPENGL_SPEKTRUM_EXPORTS; HAS_SDL_OPENGL;HAS_SDL;_WIN32PC"
- MinimalRebuild="TRUE"
- BasicRuntimeChecks="3"
- RuntimeLibrary="1"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="4"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="opengl32.lib"
- OutputFile="$(OutDir)/opengl_spectrum.vis"
- LinkIncremental="2"
- GenerateDebugInformation="TRUE"
- ProgramDatabaseFile="$(OutDir)/opengl_spektrum.pdb"
- SubSystem="2"
- ImportLibrary="$(OutDir)/opengl_spektrum.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- <Configuration
- Name="Release|Win32"
- OutputDirectory="Release"
- IntermediateDirectory="Release"
- ConfigurationType="2"
- CharacterSet="2">
- <Tool
- Name="VCCLCompilerTool"
- PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAS_SDL_OPENGL;HAS_SDL;_WIN32PC"
- RuntimeLibrary="0"
- UsePrecompiledHeader="0"
- WarningLevel="3"
- Detect64BitPortabilityProblems="TRUE"
- DebugInformationFormat="3"/>
- <Tool
- Name="VCCustomBuildTool"/>
- <Tool
- Name="VCLinkerTool"
- AdditionalDependencies="opengl32.lib winmm.lib ws2_32.lib"
- OutputFile="$(OutDir)/opengl_spectrum.vis"
- LinkIncremental="1"
- GenerateDebugInformation="FALSE"
- SubSystem="2"
- OptimizeReferences="2"
- EnableCOMDATFolding="2"
- ImportLibrary="$(OutDir)/opengl_spektrum.lib"
- TargetMachine="1"/>
- <Tool
- Name="VCMIDLTool"/>
- <Tool
- Name="VCPostBuildEventTool"/>
- <Tool
- Name="VCPreBuildEventTool"/>
- <Tool
- Name="VCPreLinkEventTool"/>
- <Tool
- Name="VCResourceCompilerTool"/>
- <Tool
- Name="VCWebServiceProxyGeneratorTool"/>
- <Tool
- Name="VCXMLDataGeneratorTool"/>
- <Tool
- Name="VCWebDeploymentTool"/>
- <Tool
- Name="VCManagedWrapperGeneratorTool"/>
- <Tool
- Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
- </Configuration>
- </Configurations>
- <References>
- </References>
- <Files>
- <Filter
- Name="Quelldateien"
- Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
- UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
- <File
- RelativePath=".\opengl_spectrum.cpp">
- </File>
- </Filter>
- <Filter
- Name="Headerdateien"
- Filter="h;hpp;hxx;hm;inl;inc;xsd"
- UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
- <File
- RelativePath=".\opengl_spectrum.h">
- </File>
- </Filter>
- <Filter
- Name="Ressourcendateien"
- Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
- UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
- </Filter>
- <File
- RelativePath=".\ReadMe.txt">
- </File>
- </Files>
- <Globals>
- </Globals>
-</VisualStudioProject>
+<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="opengl_spectrum" + ProjectGUID="{0D91724A-E6F6-4708-AF47-9F88BBE2114B}" + Keyword="Win32Proj" + TargetFrameworkVersion="131072" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="Debug" + IntermediateDirectory="Debug" + ConfigurationType="2" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;OPENGL_SPEKTRUM_EXPORTS; HAS_SDL_OPENGL;HAS_SDL;_WIN32PC" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="1" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="opengl32.lib" + OutputFile="../../../addons/visualisations/GLSpectrum/opengl_spectrum_win32.vis" + LinkIncremental="2" + GenerateDebugInformation="true" + ProgramDatabaseFile="$(OutDir)/opengl_spektrum.pdb" + SubSystem="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + ImportLibrary="$(OutDir)/opengl_spektrum.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="Release" + IntermediateDirectory="Release" + ConfigurationType="2" + InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" + CharacterSet="2" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;HAS_SDL_OPENGL;HAS_SDL;_WIN32PC" + RuntimeLibrary="0" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="opengl32.lib winmm.lib ws2_32.lib" + OutputFile="$(OutDir)/opengl_spectrum.vis" + LinkIncremental="1" + GenerateDebugInformation="false" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + RandomizedBaseAddress="1" + DataExecutionPrevention="0" + ImportLibrary="$(OutDir)/opengl_spektrum.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Quelldateien" + Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\opengl_spectrum.cpp" + > + </File> + </Filter> + <Filter + Name="Headerdateien" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\opengl_spectrum.h" + > + </File> + </Filter> + <Filter + Name="Ressourcendateien" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + </Filter> + <File + RelativePath=".\ReadMe.txt" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/xbmc/visualizations/Visualisation.cpp b/xbmc/visualizations/Visualisation.cpp index 655bbea9fc..39c0270688 100644 --- a/xbmc/visualizations/Visualisation.cpp +++ b/xbmc/visualizations/Visualisation.cpp @@ -19,12 +19,10 @@ * */ #include "system.h" -// Visualisation.cpp: implementation of the CVisualisation class. -// -////////////////////////////////////////////////////////////////////// - #include "Visualisation.h" -#include "visualizations/VisualisationTypes.h" +#include "fft.h" +#include "utils/GUIInfoManager.h" +#include "Application.h" #include "MusicInfoTag.h" #include "Settings.h" #include "WindowingFactory.h" @@ -37,49 +35,112 @@ using namespace std; using namespace MUSIC_INFO; +using namespace ADDON; -////////////////////////////////////////////////////////////////////// -// Construction/Destruction -////////////////////////////////////////////////////////////////////// +CAudioBuffer::CAudioBuffer(int iSize) +{ + m_iLen = iSize; + m_pBuffer = new short[iSize]; +} -CVisualisation::CVisualisation(struct Visualisation* pVisz, DllVisualisation* pDll, - const CStdString& strVisualisationName, - const CStdString& strSubModuleName) - : m_pVisz(pVisz) - , m_pDll(pDll) - , m_strVisualisationName(strVisualisationName) - , m_strSubModuleName(strSubModuleName) -{} +CAudioBuffer::~CAudioBuffer() +{ + delete [] m_pBuffer; +} -CVisualisation::~CVisualisation() +const short* CAudioBuffer::Get() const { + return m_pBuffer; } -void CVisualisation::Create(int posx, int posy, int width, int height) +void CAudioBuffer::Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample) { - // allow vis. to create internal things needed - // pass it the location,width,height - // and the name of the visualisation. - char szTmp[129]; - sprintf(szTmp, "create:%ix%i at %ix%i %s\n", width, height, posx, posy, m_strVisualisationName.c_str()); - OutputDebugString(szTmp); - - float pixelRatio = g_settings.m_ResInfo[g_graphicsContext.GetVideoResolution()].fPixelRatio; -#ifdef HAS_DX - // TODO LINUX this is obviously not good, but until we have visualization sorted out, this will have to do - m_pVisz->Create (g_Windowing.Get3DDevice(), posx, posy, width, height, m_strVisualisationName.c_str(), - pixelRatio, m_strSubModuleName=="" ? NULL : m_strSubModuleName.c_str() ); -#else - m_pVisz->Create (0, posx, posy, width, height, m_strVisualisationName.c_str(), pixelRatio, - m_strSubModuleName=="" ? NULL : m_strSubModuleName.c_str() ); -#endif + if (iSize<0) + { + return; + } + + if (iBitsPerSample == 16) + { + iSize /= 2; + for (int i = 0; i < iSize && i < m_iLen; i++) + { // 16 bit -> convert to short directly + m_pBuffer[i] = ((short *)psBuffer)[i]; + } + } + else if (iBitsPerSample == 8) + { + for (int i = 0; i < iSize && i < m_iLen; i++) + { // 8 bit -> convert to signed short by multiplying by 256 + m_pBuffer[i] = ((short)((char *)psBuffer)[i]) << 8; + } + } + else // assume 24 bit data + { + iSize /= 3; + for (int i = 0; i < iSize && i < m_iLen; i++) + { // 24 bit -> ignore least significant byte and convert to signed short + m_pBuffer[i] = (((int)psBuffer[3 * i + 1]) << 0) + (((int)((char *)psBuffer)[3 * i + 2]) << 8); + } + } + for (int i = iSize; i < m_iLen;++i) m_pBuffer[i] = 0; +} + +bool CVisualisation::Create(int x, int y, int w, int h) +{ + m_pInfo = new VIS_PROPS; + m_pInfo->x = x; + m_pInfo->y = y; + m_pInfo->width = w; + m_pInfo->height = h; + m_pInfo->pixelRatio = g_settings.m_ResInfo[g_graphicsContext.GetVideoResolution()].fPixelRatio; + + m_pInfo->name = strdup(Name().c_str()); + m_pInfo->presets = strdup(_P(Path()).c_str()); + m_pInfo->profile = strdup(_P(Profile()).c_str()); + + if (CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>::Create()) + { + // Start the visualisation + CStdString strFile = CUtil::GetFileName(g_application.CurrentFile()); + CLog::Log(LOGDEBUG, "Visualisation::Start()\n"); + try + { + m_pStruct->Start(m_iChannels, m_iSamplesPerSec, m_iBitsPerSample, strFile); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->Start() (CVisualisation::Create)"); + return false; + } + + GetPresets(); + GetSubModules(); + CreateBuffers(); + + if (g_application.m_pPlayer) + g_application.m_pPlayer->RegisterAudioCallback(this); + + return true; + } + return false; } void CVisualisation::Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const CStdString strSongName) { // notify visz. that new song has been started // pass it the nr of audio channels, sample rate, bits/sample and offcourse the songname - m_pVisz->Start(iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str()); + if (Initialized()) + { + try + { + m_pStruct->Start(iChannels, iSamplesPerSec, iBitsPerSample, strSongName.c_str()); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->Start (CVisualisation::Start)"); + } + } } void CVisualisation::AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength) @@ -89,235 +150,333 @@ void CVisualisation::AudioData(const short* pAudioData, int iAudioDataLength, fl // iAudioDataLength = length of audiodata array // pFreqData = fft-ed audio data // iFreqDataLength = length of pFreqData - m_pVisz->AudioData(const_cast<short*>(pAudioData), iAudioDataLength, pFreqData, iFreqDataLength); + if (Initialized()) + { + try + { + m_pStruct->AudioData(pAudioData, iAudioDataLength, pFreqData, iFreqDataLength); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->AudioData (CVisualisation::AudioData)"); + } + } } void CVisualisation::Render() { // ask visz. to render itself g_graphicsContext.BeginPaint(); - m_pVisz->Render(); + if (Initialized()) + { + try + { + m_pStruct->Render(); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->Render (CVisualisation::Render)"); + } + } g_graphicsContext.EndPaint(); } void CVisualisation::Stop() { - // ask visz. to cleanup - m_pVisz->Stop(); + if (g_application.m_pPlayer) g_application.m_pPlayer->UnRegisterAudioCallback(); + if (Initialized()) + { + try + { + m_pStruct->Stop(); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->Stop (CVisualisation::Stop)"); + } + } } - void CVisualisation::GetInfo(VIS_INFO *info) { - // get info from vis - m_pVisz->GetInfo(info); + if (Initialized()) + { + try + { + m_pStruct->GetInfo(info); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->GetInfo (CVisualisation::GetInfo)"); + } + } } bool CVisualisation::OnAction(VIS_ACTION action, void *param) { + if (!Initialized()) + return false; + // see if vis wants to handle the input // returns false if vis doesnt want the input // returns true if vis handled the input - if (action != VIS_ACTION_NONE && m_pVisz->OnAction) + try { - // if this is a VIS_ACTION_UPDATE_TRACK action, copy relevant - // tags from CMusicInfoTag to VisTag - if ( action == VIS_ACTION_UPDATE_TRACK && param ) + if (action != VIS_ACTION_NONE && m_pStruct->OnAction) { - const CMusicInfoTag* tag = (const CMusicInfoTag*)param; - VisTrack track; - - track.title = tag->GetTitle().c_str(); - track.artist = tag->GetArtist().c_str(); - track.album = tag->GetAlbum().c_str(); - track.albumArtist = tag->GetAlbumArtist().c_str(); - track.genre = tag->GetGenre().c_str(); - track.comment = tag->GetComment().c_str(); - track.lyrics = tag->GetLyrics().c_str(); - track.trackNumber = tag->GetTrackNumber(); - track.discNumber = tag->GetDiscNumber(); - track.duration = tag->GetDuration(); - track.year = tag->GetYear(); - track.rating = tag->GetRating(); - - return m_pVisz->OnAction((int)action, (void*)(&track)); + // if this is a VIS_ACTION_UPDATE_TRACK action, copy relevant + // tags from CMusicInfoTag to VisTag + if ( action == VIS_ACTION_UPDATE_TRACK && param ) + { + const CMusicInfoTag* tag = (const CMusicInfoTag*)param; + VisTrack track; + track.title = tag->GetTitle().c_str(); + track.artist = tag->GetArtist().c_str(); + track.album = tag->GetAlbum().c_str(); + track.albumArtist = tag->GetAlbumArtist().c_str(); + track.genre = tag->GetGenre().c_str(); + track.comment = tag->GetComment().c_str(); + track.lyrics = tag->GetLyrics().c_str(); + track.trackNumber = tag->GetTrackNumber(); + track.discNumber = tag->GetDiscNumber(); + track.duration = tag->GetDuration(); + track.year = tag->GetYear(); + track.rating = tag->GetRating(); + + return m_pStruct->OnAction(action, &track); + } + return m_pStruct->OnAction((int)action, param); } - return m_pVisz->OnAction((int)action, param); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->OnAction (CVisualisation::OnAction)"); } return false; } - -void CVisualisation::GetSettings(vector<VisSetting> **vecSettings) +void CVisualisation::OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample) { - if (vecSettings) *vecSettings = NULL; - if (m_pVisz->GetSettings) - { - unsigned int iEntries; - StructSetting** sSet; - iEntries = m_pVisz->GetSettings(&sSet); - VisUtils::StructToVec(iEntries, &sSet, &m_vecSettings); - if(m_pVisz->FreeSettings) - m_pVisz->FreeSettings(); - } - *vecSettings = &m_vecSettings; + if (!m_pStruct) + return ; + CLog::Log(LOGDEBUG, "OnInitialize() started"); + + m_iChannels = iChannels; + m_iSamplesPerSec = iSamplesPerSec; + m_iBitsPerSample = iBitsPerSample; + UpdateTrack(); + + CLog::Log(LOGDEBUG, "OnInitialize() done"); } -void CVisualisation::UpdateSetting(int num, vector<VisSetting> **vecSettings) +void CVisualisation::OnAudioData(const unsigned char* pAudioData, int iAudioDataLength) { - if (m_pVisz->UpdateSetting) + if (!m_pStruct) + return ; + if (Initialized()) + + // FIXME: iAudioDataLength should never be less than 0 + if (iAudioDataLength<0) + return; + + // Save our audio data in the buffers + auto_ptr<CAudioBuffer> pBuffer ( new CAudioBuffer(2*AUDIO_BUFFER_SIZE) ); + pBuffer->Set(pAudioData, iAudioDataLength, m_iBitsPerSample); + m_vecBuffers.push_back( pBuffer.release() ); + + if ( (int)m_vecBuffers.size() < m_iNumBuffers) return ; + + auto_ptr<CAudioBuffer> ptrAudioBuffer ( m_vecBuffers.front() ); + m_vecBuffers.pop_front(); + // Fourier transform the data if the vis wants it... + if (m_bWantsFreq) { - unsigned int iEntries; - StructSetting** sSet; - iEntries = VisUtils::VecToStruct(m_vecSettings, &sSet); - m_pVisz->UpdateSetting(num, &sSet); - VisUtils::FreeStruct(iEntries, &sSet); + // Convert to floats + const short* psAudioData = ptrAudioBuffer->Get(); + for (int i = 0; i < 2*AUDIO_BUFFER_SIZE; i++) + { + m_fFreq[i] = (float)psAudioData[i]; + } + + // FFT the data + twochanwithwindow(m_fFreq, AUDIO_BUFFER_SIZE); + + // Normalize the data + float fMinData = (float)AUDIO_BUFFER_SIZE * AUDIO_BUFFER_SIZE * 3 / 8 * 0.5 * 0.5; // 3/8 for the Hann window, 0.5 as minimum amplitude + float fInvMinData = 1.0f/fMinData; + for (int i = 0; i < AUDIO_BUFFER_SIZE + 2; i++) + { + m_fFreq[i] *= fInvMinData; + } + + // Transfer data to our visualisation + AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, m_fFreq, AUDIO_BUFFER_SIZE); + } + else + { // Transfer data to our visualisation + AudioData(ptrAudioBuffer->Get(), AUDIO_BUFFER_SIZE, NULL, 0); } + return ; } -void CVisualisation::GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked) +void CVisualisation::CreateBuffers() { - if (m_pVisz->GetPresets) - m_pVisz->GetPresets(pPresets, currentPreset, numPresets, locked); + ClearBuffers(); + + // Get the number of buffers from the current vis + VIS_INFO info; + m_pStruct->GetInfo(&info); + m_iNumBuffers = info.iSyncDelay + 1; + m_bWantsFreq = (info.bWantsFreq != 0); + if (m_iNumBuffers > MAX_AUDIO_BUFFERS) + m_iNumBuffers = MAX_AUDIO_BUFFERS; + if (m_iNumBuffers < 1) + m_iNumBuffers = 1; } -int CVisualisation::GetSubModules(map<string, string>& subModules) +void CVisualisation::ClearBuffers() { - if (m_pVisz->GetSubModules) + m_bWantsFreq = false; + m_iNumBuffers = 0; + + while (m_vecBuffers.size() > 0) { - char **names, **paths; - int count = m_pVisz->GetSubModules(&names, &paths); - if ( count > 0 ) - { - while ( count > 0 ) - { - count--; - subModules[ string( names[count] ) ] = string( paths[count] ); - free( names[count] ); - free( paths[count] ); - } - free( names ); - free( paths ); - return subModules.size(); - } + CAudioBuffer* pAudioBuffer = m_vecBuffers.front(); + delete pAudioBuffer; + m_vecBuffers.pop_front(); + } + for (int j = 0; j < AUDIO_BUFFER_SIZE*2; j++) + { + m_fFreq[j] = 0.0f; } - return 0; } -void CVisualisation::GetCurrentPreset(char **pPreset, bool *locked) +bool CVisualisation::UpdateTrack() { - if (pPreset && locked && m_pVisz->GetPresets) + bool handled; + if (Initialized()) { - char **presets = NULL; - int currentPreset = 0; - int numPresets = 0; - *locked = false; - m_pVisz->GetPresets(&presets, ¤tPreset, &numPresets, locked); - if (presets && currentPreset < numPresets) - *pPreset = presets[currentPreset]; + // get the current album art filename + m_AlbumThumb = _P(g_infoManager.GetImage(MUSICPLAYER_COVER, WINDOW_INVALID)); + + // get the current track tag + const CMusicInfoTag* tag = g_infoManager.GetCurrentSongTag(); + + if (m_AlbumThumb == "DefaultAlbumCover.png") + m_AlbumThumb = ""; + else + CLog::Log(LOGDEBUG,"Updating visualisation albumart: %s", m_AlbumThumb.c_str()); + + // inform the visualisation of the current album art + if ( m_pStruct->OnAction( VIS_ACTION_UPDATE_ALBUMART, + (void*)( m_AlbumThumb.c_str() ) ) ) + handled = true; + + // inform the visualisation of the current track's tag information + if ( tag && m_pStruct->OnAction( VIS_ACTION_UPDATE_TRACK, + (void*)tag ) ) + handled = true; } + return handled; } -bool CVisualisation::IsLocked() +bool CVisualisation::GetPresetList(std::vector<CStdString> &vecpresets) { - char *preset; - bool locked = false; - GetCurrentPreset(&preset, &locked); - return locked; + vecpresets = m_presets; + return !m_presets.empty(); } -char *CVisualisation::GetPreset() +bool CVisualisation::GetPresets() { - char *preset = NULL; - bool locked = false; - GetCurrentPreset(&preset, &locked); - return preset; + m_presets.clear(); + char **presets = NULL; + unsigned int entries = 0; + try + { + entries = m_pStruct->GetPresets(&presets); + } + catch (std::exception e) + { + HandleException(e, "m_pStruct->OnAction (CVisualisation::GetPresets)"); + return false; + } + if (presets && entries > 0) + { + for (unsigned i=0; i < entries; i++) + { + if (presets[i]) + { + m_presets.push_back(presets[i]); + } + } + } + return (!m_presets.empty()); } -CStdString CVisualisation::GetFriendlyName(const char* strVisz, - const char* strSubModule) +bool CVisualisation::GetSubModuleList(std::vector<CStdString> &vecmodules) { - // should be of the format "moduleName (visName)" - return CStdString(strSubModule) + " (" + CStdString(strVisz) + ")"; + vecmodules = m_submodules; + return !m_submodules.empty(); } -CStdString CVisualisation::GetFriendlyName(const char* combinedName) +bool CVisualisation::GetSubModules() { - CStdString moduleName; - CStdString visName = combinedName; - int colonPos = visName.ReverseFind(":"); - - if ( colonPos > 0 ) + m_submodules.clear(); + char **modules = NULL; + unsigned int entries = 0; + try { - visName = visName.Mid( colonPos + 1 ); - moduleName = visName.Mid( 0, colonPos - 5 ); // remove .mvis - - // should be of the format "moduleName (visName)" - return moduleName + " (" + visName + ")"; + entries = m_pStruct->GetSubModules(&modules); } - return visName.Left( visName.size() - 4 ); + catch (...) + { + CLog::Log(LOGERROR, "Exception in Visualisation::GetSubModules()"); + return false; + } + if (modules && entries > 0) + { + for (unsigned i=0; i < entries; i++) + { + if (modules[i]) + { + m_submodules.push_back(modules[i]); + } + } + } + return (!m_submodules.empty()); } -CStdString CVisualisation::GetCombinedName(const char* strVisz, - const char* strSubModule) +CStdString CVisualisation::GetFriendlyName(const CStdString& strVisz, + const CStdString& strSubModule) { - // should be of the format "visName.mvis:moduleName" - return CStdString(strVisz) + ":" + CStdString(strSubModule); + // should be of the format "moduleName (visName)" + return CStdString(strSubModule + " (" + strVisz + ")"); } -CStdString CVisualisation::GetCombinedName(const char* friendlyName) +bool CVisualisation::IsLocked() { - CStdString moduleName; - CStdString fName = friendlyName; - - // convert from "module name (vis name)" to "vis name.mvis:module name" - int startPos = fName.ReverseFind(" ("); + return false; +} - if ( startPos > 0 ) +unsigned CVisualisation::GetPreset() +{ + unsigned index = 0; + try + { + index = m_pStruct->GetPreset(); + } + catch(...) { - int endPos = fName.ReverseFind(")"); - CStdString moduleName = fName.Left( startPos ); - CStdString visName = fName.Mid( startPos+2, endPos-startPos-2 ); - return visName + ".mvis" + ":" + moduleName; + return 0; } - return fName + ".vis"; + return index; } -bool CVisualisation::IsValidVisualisation(const CStdString& strVisz) +CStdString CVisualisation::GetPresetName() { - bool bRet = true; - CStdString strExtension; - - if(strVisz.Equals("None")) - return true; - - CUtil::GetExtension(strVisz, strExtension); - if (strExtension == ".mvis") - return true; // assume multivis are OK - - if (strExtension != ".vis") - return false; - -#ifdef _LINUX - CStdString visPath(strVisz); - if(visPath.Find("/") == -1) - { - visPath.Format("%s%s", "special://xbmc/visualisations/", strVisz); - if(!XFILE::CFile::Exists(visPath)) - visPath.Format("%s%s", "special://home/visualisations/", strVisz); - } - void *handle = dlopen( _P(visPath).c_str(), RTLD_LAZY ); - if (!handle) - bRet = false; + if (!m_presets.empty()) + return m_presets[GetPreset()]; else - dlclose(handle); -#elif defined(HAS_DX) - if(strVisz.Right(11).CompareNoCase("win32dx.vis") != 0) - bRet = false; -#elif defined(_WIN32) - if(strVisz.Right(9).CompareNoCase("win32.vis") != 0) - bRet = false; -#endif - - return bRet; + return ""; } + diff --git a/xbmc/visualizations/Visualisation.h b/xbmc/visualizations/Visualisation.h index ab844ffc43..b53aa535e8 100644 --- a/xbmc/visualizations/Visualisation.h +++ b/xbmc/visualizations/Visualisation.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Team XBMC + * Copyright (C) 2005-2009 Team XBMC * http://www.xbmc.org * * This Program is free software; you can redistribute it and/or modify @@ -18,70 +18,90 @@ * http://www.gnu.org/copyleft/gpl.html * */ -// Visualisation.h: interface for the CVisualisation class. -// -////////////////////////////////////////////////////////////////////// - -#if !defined(AFX_Visualisation_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_) -#define AFX_Visualisation_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_ - -#if _MSC_VER > 1000 #pragma once -#endif // _MSC_VER > 1000 + #include "Key.h" #include "DllVisualisation.h" +#include "utils/AddonDll.h" +#include "cores/IAudioCallback.h" #include <map> +#include <list> #include <memory> -class CVisualisation +#define AUDIO_BUFFER_SIZE 512 // MUST BE A POWER OF 2!!! +#define MAX_AUDIO_BUFFERS 16 + +class CCriticalSection; + +class CAudioBuffer { public: - enum VIS_ACTION { VIS_ACTION_NONE = 0, - VIS_ACTION_NEXT_PRESET, - VIS_ACTION_PREV_PRESET, - VIS_ACTION_LOAD_PRESET, - VIS_ACTION_RANDOM_PRESET, - VIS_ACTION_LOCK_PRESET, - VIS_ACTION_RATE_PRESET_PLUS, - VIS_ACTION_RATE_PRESET_MINUS, - VIS_ACTION_UPDATE_ALBUMART, - VIS_ACTION_UPDATE_TRACK - }; - CVisualisation(struct Visualisation* pVisz, DllVisualisation* pDll, - const CStdString& strVisualisationName, const CStdString& strSubModuleName); - ~CVisualisation(); + CAudioBuffer(int iSize); + virtual ~CAudioBuffer(); + const short* Get() const; + void Set(const unsigned char* psBuffer, int iSize, int iBitsPerSample); +private: + CAudioBuffer(); + short* m_pBuffer; + int m_iLen; +}; - void Create(int posx, int posy, int width, int height); - void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const CStdString strSongName); - void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); - void Render(); - void Stop(); - void GetInfo(VIS_INFO *info); - bool OnAction(VIS_ACTION action, void *param = NULL); - void GetSettings(std::vector<VisSetting> **vecSettings); - void UpdateSetting(int num, std::vector<VisSetting> **vecSettings); - void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked); - void GetCurrentPreset(char **pPreset, bool *locked); - int GetSubModules(std::map<std::string, std::string>& subModules); - bool IsLocked(); - char *GetPreset(); +namespace ADDON +{ + class CVisualisation : public CAddonDll<DllVisualisation, Visualisation, VIS_PROPS> + , public IAudioCallback + { + public: + CVisualisation(const ADDON::AddonProps &props) : CAddonDll<DllVisualisation, Visualisation, VIS_PROPS>(props) {} + virtual void OnInitialize(int iChannels, int iSamplesPerSec, int iBitsPerSample); + virtual void OnAudioData(const unsigned char* pAudioData, int iAudioDataLength); + bool Create(int x, int y, int w, int h); + void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const CStdString strSongName); + void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); + void Render(); + void Stop(); + void GetInfo(VIS_INFO *info); + bool OnAction(VIS_ACTION action, void *param = NULL); + bool UpdateTrack(); + bool HasSubModules() { return !m_submodules.empty(); } + bool IsLocked(); + unsigned GetPreset(); + CStdString GetPresetName(); + bool GetPresetList(std::vector<CStdString>& vecpresets); + bool GetSubModuleList(std::vector<CStdString>& vecmodules); + static CStdString GetFriendlyName(const CStdString& vis, const CStdString& module); - // some helper functions - static CStdString GetFriendlyName(const char* strVisz, const char* strSubModule); - static CStdString GetFriendlyName(const char* combinedName); - static CStdString GetCombinedName(const char* strVisz, const char* strSubModule); - static CStdString GetCombinedName(const char* friendlyName); - static bool IsValidVisualisation(const CStdString& strVisz); + private: + void CreateBuffers(); + void ClearBuffers(); -protected: - std::auto_ptr<struct Visualisation> m_pVisz; - std::auto_ptr<DllVisualisation> m_pDll; - CStdString m_strVisualisationName; - CStdString m_strSubModuleName; + bool GetPresets(); + bool GetSubModules(); - std::vector<VisSetting> m_vecSettings; -}; + // attributes of the viewport we render to + int m_xPos; + int m_yPos; + int m_width; + int m_height; + // cached preset list + std::vector<CStdString> m_presets; + // cached submodule list + std::vector<CStdString> m_submodules; + int m_currentModule; -#endif // !defined(AFX_Visualisation_H__99B9A52D_ED09_4540_A887_162A68217A31__INCLUDED_) + // audio properties + int m_iChannels; + int m_iSamplesPerSec; + int m_iBitsPerSample; + std::list<CAudioBuffer*> m_vecBuffers; + int m_iNumBuffers; // Number of Audio buffers + bool m_bWantsFreq; + float m_fFreq[2*AUDIO_BUFFER_SIZE]; // Frequency data + bool m_bCalculate_Freq; // True if the vis wants freq data + + // track information + CStdString m_AlbumThumb; + }; +} diff --git a/xbmc/visualizations/VisualisationFactory.cpp b/xbmc/visualizations/VisualisationFactory.cpp deleted file mode 100644 index 39d112ccea..0000000000 --- a/xbmc/visualizations/VisualisationFactory.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2005-2008 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ -#include "system.h" -#include "VisualisationFactory.h" -#include "Util.h" -#include "FileSystem/File.h" - -using namespace XFILE; - -CVisualisationFactory::CVisualisationFactory() -{ - -} - -CVisualisationFactory::~CVisualisationFactory() -{ - -} - -CVisualisation* CVisualisationFactory::LoadVisualisation(const CStdString& strVisz) const -{ - CStdString nullModule = ""; - return LoadVisualisation( strVisz, nullModule ); -} - -CVisualisation* CVisualisationFactory::LoadVisualisation(const CStdString& strVisz, - const CStdString& strSubModule) const -{ - // strip of the path & extension to get the name of the visualisation - // like goom or spectrum - CStdString strFileName = strVisz; - CStdString strName = CUtil::GetFileName(strVisz); - - // if it's a relative path or just a name, convert to absolute path - if ( strFileName[1] != ':' && strFileName[0] != '/' ) - { - // first check home - strFileName.Format("special://home/visualisations/%s", strName.c_str() ); - - // if not found, use system - if ( ! CFile::Exists( strFileName ) ) - strFileName.Format("special://xbmc/visualisations/%s", strName.c_str() ); - } - strName = strName.Left(strName.ReverseFind('.')); - -#ifdef HAS_VISUALISATION - // load visualisation - DllVisualisation* pDll = new DllVisualisation; - pDll->SetFile(strFileName); - // FIXME: Some Visualisations do not work - // when their dll is not unloaded immediatly - pDll->EnableDelayedUnload(false); - if (!pDll->Load()) - { - delete pDll; - return NULL; - } - - struct Visualisation* pVisz = (struct Visualisation*)malloc(sizeof(struct Visualisation)); - ZeroMemory(pVisz, sizeof(struct Visualisation)); - pDll->GetModule(pVisz); - - // and pass it to a new instance of CVisualisation() which will hanle the visualisation - return new CVisualisation(pVisz, pDll, strName, strSubModule); -#else - return NULL; -#endif -} diff --git a/xbmc/visualizations/VisualisationTypes.h b/xbmc/visualizations/VisualisationTypes.h deleted file mode 100644 index ad1146f6db..0000000000 --- a/xbmc/visualizations/VisualisationTypes.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2005-2009 Team XBMC - * http://www.xbmc.org - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with XBMC; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * http://www.gnu.org/copyleft/gpl.html - * - */ - -/* - Common data structures shared between XBMC and XBMC's visualisations - */ - -#ifndef __VISUALISATION_TYPES_H__ -#define __VISUALISATION_TYPES_H__ - -#include <vector> - -extern "C" -{ - //////////////////////////////////////////////////////////////////// - // The VIS_INFO structure to tell XBMC what data you need. - //////////////////////////////////////////////////////////////////// - struct VIS_INFO - { - bool bWantsFreq; - int iSyncDelay; - }; - - //////////////////////////////////////////////////////////////////// - // The VisTrack class for track tag information - //////////////////////////////////////////////////////////////////// - class VisTrack - { - public: - VisTrack() - { - title = artist = album = albumArtist = NULL; - genre = comment = lyrics = reserved1 = reserved2 = NULL; - trackNumber = discNumber = duration = year = 0; - rating = 0; - reserved3 = reserved4 = 0; - } - - const char *title; - const char *artist; - const char *album; - const char *albumArtist; - const char *genre; - const char *comment; - const char *lyrics; - const char *reserved1; - const char *reserved2; - - int trackNumber; - int discNumber; - int duration; - int year; - char rating; - int reserved3; - int reserved4; - }; - - //////////////////////////////////////////////////////////////////// - // The VisSetting class for GUI settings for vis. - //////////////////////////////////////////////////////////////////// - class VisSetting - { - public: - enum SETTING_TYPE { NONE=0, CHECK, SPIN }; - - VisSetting(SETTING_TYPE t, const char *label) - { - name = NULL; - if (label) - { - name = new char[strlen(label)+1]; - strcpy(name, label); - } - current = 0; - type = t; - } - - VisSetting(const VisSetting &rhs) // copy constructor - { - name = NULL; - if (rhs.name) - { - name = new char[strlen(rhs.name)+1]; - strcpy(name, rhs.name); - } - current = rhs.current; - type = rhs.type; - for (unsigned int i = 0; i < rhs.entry.size(); i++) - { - char *lab = new char[strlen(rhs.entry[i]) + 1]; - strcpy(lab, rhs.entry[i]); - entry.push_back(lab); - } - } - - ~VisSetting() - { - if (name) - delete[] name; - for (unsigned int i=0; i < entry.size(); i++) - delete[] entry[i]; - } - - void AddEntry(const char *label) - { - if (!label || type != SPIN) return; - char *lab = new char[strlen(label) + 1]; - strcpy(lab, label); - entry.push_back(lab); - } - - // data members - SETTING_TYPE type; - char* name; - int current; - std::vector<const char *> entry; - }; - - //////////////////////////////// - typedef struct - { - public: - int type; - char* name; - int current; - char** entry; - unsigned int entry_elements; - } StructSetting; - - class VisUtils - { - public: - - static unsigned int VecToStruct(std::vector<VisSetting> &vecSet, StructSetting*** sSet) - { - *sSet = NULL; - if(vecSet.size() == 0) - return 0; - - unsigned int uiElements=0; - - *sSet = (StructSetting**)malloc(vecSet.size()*sizeof(StructSetting*)); - for(unsigned int i=0;i<vecSet.size();i++) - { - (*sSet)[i] = NULL; - (*sSet)[i] = (StructSetting*)malloc(sizeof(StructSetting)); - (*sSet)[i]->name = NULL; - uiElements++; - - if (vecSet[i].name) - { - (*sSet)[i]->name = (char*)malloc(strlen(vecSet[i].name)*sizeof(char*)+1); - strcpy((*sSet)[i]->name, vecSet[i].name); - (*sSet)[i]->type = vecSet[i].type; - (*sSet)[i]->current = vecSet[i].current; - (*sSet)[i]->entry_elements = 0; - (*sSet)[i]->entry = NULL; - if(vecSet[i].type == VisSetting::SPIN && vecSet[i].entry.size() > 0) - { - (*sSet)[i]->entry = (char**)malloc(vecSet[i].entry.size()*sizeof(char**)); - for(unsigned int j=0;j<vecSet[i].entry.size();j++) - { - if(strlen(vecSet[i].entry[j]) > 0) - { - (*sSet)[i]->entry[j] = (char*)malloc(strlen(vecSet[i].entry[j])*sizeof(char*)+1); - strcpy((*sSet)[i]->entry[j], vecSet[i].entry[j]); - (*sSet)[i]->entry_elements++; - } - } - } - } - } - return uiElements; - } - - static void StructToVec(unsigned int iElements, StructSetting*** sSet, std::vector<VisSetting> *vecSet) - { - if(iElements == 0) - return; - - vecSet->clear(); - for(unsigned int i=0;i<iElements;i++) - { - VisSetting vSet((VisSetting::SETTING_TYPE)(*sSet)[i]->type, (*sSet)[i]->name); - if((*sSet)[i]->type == VisSetting::SPIN) - { - for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++) - { - vSet.AddEntry((*sSet)[i]->entry[j]); - } - } - vSet.current = (*sSet)[i]->current; - vecSet->push_back(vSet); - } - } - - static void FreeStruct(unsigned int iElements, StructSetting*** sSet) - { - if(iElements == 0) - return; - - for(unsigned int i=0;i<iElements;i++) - { - if((*sSet)[i]->type == VisSetting::SPIN) - { - for(unsigned int j=0;j<(*sSet)[i]->entry_elements;j++) - { - if((*sSet)[i]->entry[j]) - free((*sSet)[i]->entry[j]); - } - if((*sSet)[i]->entry) - free((*sSet)[i]->entry); - } - if((*sSet)[i]->name) - free((*sSet)[i]->name); - if((*sSet)[i]) - free((*sSet)[i]); - } - if(*sSet) - free(*sSet); - } - }; - - struct Visualisation - { - public: - void (__cdecl* Create)(void* unused, int iPosX, int iPosY, int iWidth, int iHeight, - const char* szVisualisation,float pixelRatio, const char *szSubModule); - void (__cdecl* Start)(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName); - void (__cdecl* AudioData)(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength); - void (__cdecl* Render) (); - void (__cdecl* Stop)(); - void (__cdecl* GetInfo)(VIS_INFO *info); - bool (__cdecl* OnAction)(long flags, void *param); - void (__cdecl *FreeSettings)(); - unsigned int (__cdecl *GetSettings)(StructSetting*** sSet); - void (__cdecl *UpdateSetting)(int num, StructSetting*** sSet); - void (__cdecl *GetPresets)(char ***pPresets, int *currentPreset, int *numPresets, bool *locked); - int (__cdecl *GetSubModules)(char ***names, char ***paths); - }; - -} - -#endif //__VISUALISATION_TYPES_H__ diff --git a/xbmc/visualizations/WaveForm/Main.cpp b/xbmc/visualizations/WaveForm/Main.cpp index 4a61936fe8..95a600b3d1 100644 --- a/xbmc/visualizations/WaveForm/Main.cpp +++ b/xbmc/visualizations/WaveForm/Main.cpp @@ -1,15 +1,14 @@ // Waveform.vis
// A simple visualisation example by MrC
-#include "../../../visualisations/xbmc_vis.h"
-#ifdef _WIN32
+#include "../../addons/include/xbmc_vis_dll.h"
+#include <stdio.h>
#ifdef HAS_SDL_OPENGL
#include <GL/glew.h>
#else
+#ifdef _WIN32
#include <D3D9.h>
#endif
-#else
-#include "../../../guilib/system.h"
#endif
char g_visName[512];
@@ -29,10 +28,8 @@ typedef struct { int MinZ;
int MaxZ;
} D3DVIEWPORT9;
-#ifdef _WIN32
typedef unsigned long D3DCOLOR;
#endif
-#endif
D3DVIEWPORT9 g_viewport;
@@ -47,25 +44,28 @@ struct Vertex_t #endif
//-- Create -------------------------------------------------------------------
-// Called once when the visualisation is created by XBMC. Do any setup here.
+// Called on load. Addon should fully initalize or return error status
//-----------------------------------------------------------------------------
-extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth, int iHeight, const char* szVisualisationName,
- float fPixelRatio, const char *szSubModuleName)
+ADDON_STATUS Create(void* hdl, void* props)
{
- //printf("Creating Waveform\n");
- strcpy(g_visName, szVisualisationName);
- m_uiVisElements = 0;
+ if (!props)
+ return STATUS_UNKNOWN;
+
+ VIS_PROPS* visProps = (VIS_PROPS*)props;
+
#ifndef HAS_SDL_OPENGL
- g_device = (LPDIRECT3DDEVICE9)pd3dDevice;
+ g_device = (LPDIRECT3DDEVICE9)visProps->device;
#else
- g_device = pd3dDevice;
+ g_device = visProps->device;
#endif
- g_viewport.X = iPosX;
- g_viewport.Y = iPosY;
- g_viewport.Width = iWidth;
- g_viewport.Height = iHeight;
+ g_viewport.X = visProps->x;
+ g_viewport.Y = visProps->y;
+ g_viewport.Width = visProps->width;
+ g_viewport.Height = visProps->height;
g_viewport.MinZ = 0;
g_viewport.MaxZ = 1;
+
+ return STATUS_OK;
}
//-- Start --------------------------------------------------------------------
@@ -87,7 +87,7 @@ extern "C" void Stop() //-- Audiodata ----------------------------------------------------------------
// Called by XBMC to pass new audio data to the vis
//-----------------------------------------------------------------------------
-extern "C" void AudioData(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
+extern "C" void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
{
// Convert the audio data into a floating -1 to +1 range
int ipos=0;
@@ -187,7 +187,7 @@ extern "C" void GetInfo(VIS_INFO* pInfo) //-- OnAction -----------------------------------------------------------------
// Handle XBMC actions such as next preset, lock preset, album art changed etc
//-----------------------------------------------------------------------------
-extern "C" bool OnAction(long flags, void *param)
+extern "C" bool OnAction(long flags, const void *param)
{
bool ret = false;
return ret;
@@ -196,37 +196,85 @@ extern "C" bool OnAction(long flags, void *param) //-- GetPresets ---------------------------------------------------------------
// Return a list of presets to XBMC for display
//-----------------------------------------------------------------------------
-extern "C" void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked)
+extern "C" unsigned int GetPresets(char ***presets)
{
-
+ return 0;
}
-//-- GetSettings --------------------------------------------------------------
-// Return the settings for XBMC to display
+//-- GetPreset ----------------------------------------------------------------
+// Return the index of the current playing preset
//-----------------------------------------------------------------------------
-extern "C" unsigned int GetSettings(StructSetting*** sSet)
+extern "C" unsigned GetPreset()
{
return 0;
}
-extern "C" void FreeSettings()
+//-- IsLocked -----------------------------------------------------------------
+// Returns true if this add-on use settings
+//-----------------------------------------------------------------------------
+extern "C" bool IsLocked()
+{
+ return false;
+}
+
+//-- GetSubModules ------------------------------------------------------------
+// Return any sub modules supported by this vis
+//-----------------------------------------------------------------------------
+extern "C" unsigned int GetSubModules(char ***names)
+{
+ return 0; // this vis supports 0 sub modules
+}
+
+//-- Remove -------------------------------------------------------------------
+// Do everything before unload of this add-on
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" void Remove()
{
- return;
}
+//-- HasSettings --------------------------------------------------------------
+// Returns true if this add-on use settings
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" bool HasSettings()
+{
+ return false;
+}
-//-- UpdateSetting ------------------------------------------------------------
-// Handle setting change request from XBMC
+//-- GetStatus ---------------------------------------------------------------
+// Returns the current Status of this visualisation
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" ADDON_STATUS GetStatus()
+{
+ return STATUS_OK;
+}
+
+//-- GetSettings --------------------------------------------------------------
+// Return the settings for XBMC to display
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" void UpdateSetting(int num, StructSetting*** sSet)
+extern "C" unsigned int GetSettings(StructSetting ***sSet)
{
+ return 0;
+}
+//-- FreeSettings --------------------------------------------------------------
+// Free the settings struct passed from XBMC
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+
+extern "C" void FreeSettings()
+{
}
-//-- GetSubModules ------------------------------------------------------------
-// Return any sub modules supported by this vis
+//-- SetSetting ---------------------------------------------------------------
+// Set a specific Setting value (called from XBMC)
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" int GetSubModules(char ***names, char ***paths)
+extern "C" ADDON_STATUS SetSetting(const char *strSetting, const void* value)
{
- return 0; // this vis supports 0 sub modules
+ return STATUS_OK;
}
+
diff --git a/xbmc/visualizations/WaveForm/Makefile.in b/xbmc/visualizations/WaveForm/Makefile.in index 0d9a65cccb..7888d70873 100644 --- a/xbmc/visualizations/WaveForm/Makefile.in +++ b/xbmc/visualizations/WaveForm/Makefile.in @@ -1,10 +1,10 @@ ARCH=@ARCH@ -INCLUDES=-I. -I../../linux -I../../ -I ../../../guilib +INCLUDES=-I. -I../../addons/include DEFINES+=-DHAS_SDL_OPENGL -DHAS_SDL CXXFLAGS=-fPIC OBJS=Main.o -SLIB=../../../visualisations/Waveform.vis +SLIB=../../../addons/visualizations/Waveform/Waveform.vis $(SLIB): $(OBJS) ifeq ($(findstring osx,$(ARCH)), osx) diff --git a/xbmc/visualizations/XBMCProjectM/Main.cpp b/xbmc/visualizations/XBMCProjectM/Main.cpp index e390a30b63..72c91287b8 100644 --- a/xbmc/visualizations/XBMCProjectM/Main.cpp +++ b/xbmc/visualizations/XBMCProjectM/Main.cpp @@ -1,459 +1,427 @@ -
-/*
-xmms-projectM v0.99 - xmms-projectm.sourceforge.net
---------------------------------------------------
-
-Lead Developers: Carmelo Piccione (cep@andrew.cmu.edu) &
- Peter Sperl (peter@sperl.com)
-
-We have also been advised by some professors at CMU, namely Roger B. Dannenberg.
-http://www-2.cs.cmu.edu/~rbd/
-
-The inspiration for this program was Milkdrop by Ryan Geiss. Obviously.
-
-This code is distributed under the GPL.
-
-
-THANKS FOR THE CODE!!!
--------------------------------------------------
-The base for this program was andy@nobugs.org's XMMS plugin tutorial
-http://www.xmms.org/docs/vis-plugin.html
-
-We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code
-fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html
-
-For font rendering we used GLF by Roman Podobedov
-glf.c - http://astronomy.swin.edu.au/~pbourke/opengl/glf/
-
-and some beat detection code was inspired by Frederic Patin @
-www.gamedev.net/reference/programming/features/beatdetection/
---
-
-"ported" to XBMC by d4rk
-d4rk@xbmc.org
-
-*/
-
-#include "xbmc_vis.h"
-#include <GL/glew.h>
-#include "libprojectM/ConfigFile.h"
-#include "libprojectM/projectM.hpp"
-#include "libprojectM/Preset.hpp"
-#include "libprojectM/PCM.hpp"
-#include <string>
-#ifdef WIN32
-#include "libprojectM/win32-dirent.h"
-#include <io.h>
-#else
-#include "PlatformDefs.h"
-#include "Util.h"
-#include "system.h"
-#include "FileSystem/SpecialProtocol.h"
-#include <dirent.h>
-#endif
-
-#define PRESETS_DIR "special://xbmc/visualisations/projectM"
-#define CONFIG_FILE "special://profile/visualisations/projectM.conf"
-
-projectM *globalPM = NULL;
-
-extern int preset_index;
-
-// some projectm globals
-int maxSamples=512;
-int texsize=512;
-int gx=40,gy=30;
-int fps=100;
-char *disp;
-char g_visName[512];
-char **g_presets=NULL;
-int g_numPresets = 0;
-projectM::Settings g_configPM;
-std::string g_configFile;
-
-#define QUALITY_LOW "Low"
-#define QUALITY_MEDIUM "Medium"
-#define QUALITY_HIGH "High"
-#define QUALITY_MAX "Maximum"
-#define PROJECTM_QUALITY (VIS_ACTION_USER+1)
-
-// Some helper Functions
-
-// case-insensitive alpha sort from projectM's win32-dirent.cc
-#ifndef WIN32
-int alphasort(const void* lhs, const void* rhs)
-{
- const struct dirent* lhs_ent = *(struct dirent**)lhs;
- const struct dirent* rhs_ent = *(struct dirent**)rhs;
- return strcasecmp(lhs_ent->d_name, rhs_ent->d_name);
-}
-#endif
-
-// check for a valid preset extension
-#ifdef __APPLE__
-int check_valid_extension(struct dirent* ent)
-#else
-int check_valid_extension(const struct dirent* ent)
-#endif
-{
- const char* ext = 0;
-
- if (!ent) return 0;
-
- ext = strrchr(ent->d_name, '.');
- if (!ext) ext = ent->d_name;
-
- if (0 == strcasecmp(ext, ".milk")) return 1;
- if (0 == strcasecmp(ext, ".prjm")) return 1;
-
- return 0;
-}
-
-//-- Create -------------------------------------------------------------------
-// Called once when the visualisation is created by XBMC. Do any setup here.
-//-----------------------------------------------------------------------------
-extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth, int iHeight, const char* szVisualisationName,
- float fPixelRatio, const char *szSubModuleName)
-{
- strcpy(g_visName, szVisualisationName);
-
- m_vecSettings.clear();
- m_uiVisElements = 0;
-
- /** Initialise projectM */
-
-#ifdef WIN32
- g_configFile = string(CONFIG_FILE);
- std::string presetsDir = string(PRESETS_DIR);
-#else
- g_configFile = _P(CONFIG_FILE);
- std::string presetsDir = _P(PRESETS_DIR);
-#endif
-
- g_configPM.meshX = gx;
- g_configPM.meshY = gy;
- g_configPM.fps = fps;
- g_configPM.textureSize = texsize;
- g_configPM.windowWidth = iWidth;
- g_configPM.windowHeight = iHeight;
- g_configPM.presetURL = presetsDir;
- g_configPM.smoothPresetDuration = 5;
- g_configPM.presetDuration = 15;
- g_configPM.beatSensitivity = 10.0;
- g_configPM.aspectCorrection = true;
- g_configPM.easterEgg = 0.0;
- g_configPM.shuffleEnabled = true;
- g_configPM.windowLeft = iPosX;
- g_configPM.windowBottom = iPosY;
-
- {
- FILE *f;
- f = fopen(g_configFile.c_str(), "r");
- if (f) { // Config exists. Let's preserve settings except for iWidth, iHeight, iPosX, iPosY
- fclose(f);
- ConfigFile config(g_configFile.c_str());
- if (config.keyExists("Mesh X")) g_configPM.meshX = config.read<int> ("Mesh X", gx);
- if (config.keyExists("Mesh Y")) g_configPM.meshY = config.read<int> ("Mesh Y", gy);
- if (config.keyExists("Texture Size")) g_configPM.textureSize = config.read<int> ("Texture Size", texsize);
- if (config.keyExists("Preset Path")) g_configPM.presetURL = config.read<string> ("Preset Path", presetsDir);
- if (config.keyExists("Smooth Preset Duration")) g_configPM.smoothPresetDuration = config.read<int> ("Smooth Preset Duration", 5);
- if (config.keyExists("Preset Duration")) g_configPM.presetDuration = config.read<int> ("Preset Duration", 15);
- if (config.keyExists("FPS")) g_configPM.fps = config.read<int> ("FPS", fps);
- if (config.keyExists("Hard Cut Sensitivity")) g_configPM.beatSensitivity = config.read<float> ("Hard Cut Sensitivity", 10.0);
- if (config.keyExists("Aspect Correction")) g_configPM.aspectCorrection = config.read<bool> ("Aspect Correction", true);
- if (config.keyExists("Easter Egg")) g_configPM.easterEgg = config.read<float> ("Easter Egg", 0.0);
- if (config.keyExists("Shuffle Enabled")) g_configPM.shuffleEnabled = config.read<bool> ("Shuffle Enabled", true);
- if (config.keyExists("Use FBO")) g_configPM.useFBO = config.read<bool> ("Use FBO", false);
- }
- else {
-#ifndef WIN32
- CStdString strPath;
- CUtil::GetDirectory(g_configFile, strPath);
- CUtil::CreateDirectoryEx(strPath);
-#endif
- f = fopen(g_configFile.c_str(), "w"); // Config does not exist, but we still need at least a blank file.
- fclose(f);
- }
- projectM::writeConfig(g_configFile, g_configPM);
- }
-
- if (globalPM)
- delete globalPM;
-
- globalPM = new projectM(g_configFile);
-
- VisSetting quality(VisSetting::SPIN, "Render Quality");
- quality.AddEntry("Low");
- quality.AddEntry("Medium");
- quality.AddEntry("High");
- quality.AddEntry("Maximum");
- if (g_configPM.textureSize == 2048)
- {
- quality.current = 3;
- }
- else if (g_configPM.textureSize == 1024)
- {
- quality.current = 2;
- }
- else if (g_configPM.textureSize == 512)
- {
- quality.current = 1;
- }
- else if (g_configPM.textureSize == 256)
- {
- quality.current = 0;
- }
- m_vecSettings.push_back(quality);
-
- VisSetting shuffleMode(VisSetting::CHECK, "Shuffle Mode");
- shuffleMode.current = globalPM->isShuffleEnabled();
- m_vecSettings.push_back(shuffleMode);
-
- VisSetting smoothPresetDuration(VisSetting::SPIN, "Smooth Preset Duration");
- for (int i=0; i < 50; i++)
- {
- char temp[10];
- sprintf(temp, "%i secs", i);
- smoothPresetDuration.AddEntry(temp);
- }
- smoothPresetDuration.current = (int)(g_configPM.smoothPresetDuration);
- m_vecSettings.push_back(smoothPresetDuration);
-
- VisSetting presetDuration(VisSetting::SPIN, "Preset Duration");
- for (int i=0; i < 50; i++)
- {
- char temp[10];
- sprintf(temp, "%i secs", i);
- presetDuration.AddEntry(temp);
- }
- presetDuration.current = (int)(g_configPM.presetDuration);
- m_vecSettings.push_back(presetDuration);
-
- VisSetting beatSensitivity(VisSetting::SPIN, "Beat Sensitivity");
- for (int i=0; i <= 100; i++)
- {
- char temp[10];
- sprintf(temp, "%2.1f", (float)(i + 1)/5);
- beatSensitivity.AddEntry(temp);
- }
- beatSensitivity.current = (int)(g_configPM.beatSensitivity * 5 - 1);
- m_vecSettings.push_back(beatSensitivity);
-}
-
-//-- Start --------------------------------------------------------------------
-// Called when a new soundtrack is played
-//-----------------------------------------------------------------------------
-extern "C" void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName)
-{
- //printf("Got Start Command\n");
-}
-
-//-- Stop ---------------------------------------------------------------------
-// Called when the visualisation is closed by XBMC
-//-----------------------------------------------------------------------------
-extern "C" void Stop()
-{
- if (globalPM)
- {
- projectM::writeConfig(g_configFile,globalPM->settings());
- delete globalPM;
- globalPM = NULL;
- }
- if (g_presets)
- {
- for (int i = 0 ; i<g_numPresets ; i++)
- {
- free(g_presets[i]);
- }
- free(g_presets);
- g_presets = NULL;
- }
- m_vecSettings.clear();
-}
-
-//-- Audiodata ----------------------------------------------------------------
-// Called by XBMC to pass new audio data to the vis
-//-----------------------------------------------------------------------------
-extern "C" void AudioData(short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength)
-{
- globalPM->pcm()->addPCM16Data(pAudioData, iAudioDataLength);
-}
-
-
-//-- Render -------------------------------------------------------------------
-// Called once per frame. Do all rendering here.
-//-----------------------------------------------------------------------------
-extern "C" void Render()
-{
- globalPM->renderFrame();
-}
-
-//-- GetInfo ------------------------------------------------------------------
-// Tell XBMC our requirements
-//-----------------------------------------------------------------------------
-extern "C" void GetInfo(VIS_INFO* pInfo)
-{
- pInfo->bWantsFreq = false;
- pInfo->iSyncDelay = 0;
-}
-
-//-- OnAction -----------------------------------------------------------------
-// Handle XBMC actions such as next preset, lock preset, album art changed etc
-//-----------------------------------------------------------------------------
-extern "C" bool OnAction(long flags, void *param)
-{
- bool ret = false;
-
- if (flags == VIS_ACTION_LOAD_PRESET && param)
- {
- int pindex = *((int *)param);
- globalPM->selectPreset(pindex);
- ret = true;
- }
- else if (flags == VIS_ACTION_NEXT_PRESET)
- {
-// switchPreset(ALPHA_NEXT, SOFT_CUT);
- if (!globalPM->isShuffleEnabled())
- globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_n, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
- else
- globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
- ret = true;
- }
- else if (flags == VIS_ACTION_PREV_PRESET)
- {
-// switchPreset(ALPHA_PREVIOUS, SOFT_CUT);
- if (!globalPM->isShuffleEnabled())
- globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_p, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
- else
- globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS
-
- ret = true;
- }
- else if (flags == VIS_ACTION_RANDOM_PRESET)
- {
- globalPM->setShuffleEnabled(!globalPM->isShuffleEnabled());
- ret = true;
- }
- else if (flags == VIS_ACTION_LOCK_PRESET)
- {
- globalPM->setPresetLock(!globalPM->isPresetLocked());
- ret = true;
- }
- return ret;
-}
-
-//-- GetPresets ---------------------------------------------------------------
-// Return a list of presets to XBMC for display
-//-----------------------------------------------------------------------------
-extern "C" void GetPresets(char ***pPresets, int *currentPreset, int *numPresets, bool *locked)
-{
- if (!g_presets)
- {
- if (globalPM->getPlaylistSize() > 0)
- {
- g_numPresets = globalPM->getPlaylistSize();
- g_presets = (char **)malloc(sizeof(char*)*globalPM->getPlaylistSize());
- if (g_presets)
- {
- for (unsigned int i = 0; i < globalPM->getPlaylistSize() ; i++)
- {
- g_presets[i] = (char*)malloc(strlen(globalPM->getPresetName(i).c_str())+2);
- if (g_presets[i])
- {
- strcpy(g_presets[i], globalPM->getPresetName(i).c_str());
- }
- }
- }
- }
- }
-
-
- if (g_presets)
- {
- *pPresets = g_presets;
- *numPresets = g_numPresets;
- unsigned int presetIndex;
- if (globalPM->selectedPresetIndex(presetIndex) && presetIndex >= 0 &&
- (int)presetIndex < g_numPresets)
- *currentPreset = presetIndex;
- }
- *locked = globalPM->isPresetLocked();
-}
-
-//-- GetSettings --------------------------------------------------------------
-// Return the settings for XBMC to display
-//-----------------------------------------------------------------------------
-
-extern "C" unsigned int GetSettings(StructSetting*** sSet)
-{
- m_uiVisElements = VisUtils::VecToStruct(m_vecSettings, &m_structSettings);
- *sSet = m_structSettings;
- return m_uiVisElements;
-}
-
-extern "C" void FreeSettings()
-{
- VisUtils::FreeStruct(m_uiVisElements, &m_structSettings);
-}
-
-//-- UpdateSetting ------------------------------------------------------------
-// Handle setting change request from XBMC
-//-----------------------------------------------------------------------------
-extern "C" void UpdateSetting(int num, StructSetting*** sSet)
-{
- VisUtils::StructToVec(m_uiVisElements, sSet, &m_vecSettings);
- VisSetting &setting = m_vecSettings[num];
- if (strcasecmp(setting.name, "Use Preset")==0)
- OnAction(34, (void*)&setting.current);
- else if (strcasecmp(setting.name, "Shuffle Mode")==0)
- OnAction(VIS_ACTION_RANDOM_PRESET, (void*)&setting.current);
- else {
- if (globalPM)
- {
- g_configPM = globalPM->settings();
- projectM::writeConfig(g_configFile,globalPM->settings());
- delete globalPM;
- globalPM = NULL;
- }
- if (strcasecmp(setting.name, "Smooth Preset Duration")==0)
- g_configPM.smoothPresetDuration = setting.current;
- else if (strcasecmp(setting.name,"Preset Duration")==0)
- g_configPM.presetDuration = setting.current;
- else if (strcasecmp(setting.name, "Beat Sensitivity")==0)
- g_configPM.beatSensitivity = (float)(setting.current + 1) / 5.0f;
- else if (strcasecmp(setting.name, "Render Quality")==0)
- {
- if ( setting.current == 0 ) // low
- {
- g_configPM.useFBO = false;
- g_configPM.textureSize = 256;
- }
- else if ( setting.current == 1 ) // med
- {
- g_configPM.useFBO = false;
- g_configPM.textureSize = 512;
- }
- else if ( setting.current == 2 ) // high
- {
- g_configPM.useFBO = false;
- g_configPM.textureSize = 1024;
- }
- else if ( setting.current == 3 ) // max
- {
- g_configPM.useFBO = false;
- g_configPM.textureSize = 2048;
- }
- }
- projectM::writeConfig(g_configFile, g_configPM);
- globalPM = new projectM(g_configFile);
- }
-
-}
-
-//-- GetSubModules ------------------------------------------------------------
-// Return any sub modules supported by this vis
-//-----------------------------------------------------------------------------
-extern "C" int GetSubModules(char ***names, char ***paths)
-{
- return 0; // this vis supports 0 sub modules
-}
+ +/* +xmms-projectM v0.99 - xmms-projectm.sourceforge.net +-------------------------------------------------- + +Lead Developers: Carmelo Piccione (cep@andrew.cmu.edu) & + Peter Sperl (peter@sperl.com) + +We have also been advised by some professors at CMU, namely Roger B. Dannenberg. +http://www-2.cs.cmu.edu/~rbd/ + +The inspiration for this program was Milkdrop by Ryan Geiss. Obviously. + +This code is distributed under the GPL. + + +THANKS FOR THE CODE!!! +------------------------------------------------- +The base for this program was andy@nobugs.org's XMMS plugin tutorial +http://www.xmms.org/docs/vis-plugin.html + +We used some FFT code by Takuya OOURA instead of XMMS' built-in fft code +fftsg.c - http://momonga.t.u-tokyo.ac.jp/~ooura/fft.html + +For font rendering we used GLF by Roman Podobedov +glf.c - http://astronomy.swin.edu.au/~pbourke/opengl/glf/ + +and some beat detection code was inspired by Frederic Patin @ +www.gamedev.net/reference/programming/features/beatdetection/ +-- + +"ported" to XBMC by d4rk +d4rk@xbmc.org + +*/ + +#include "xbmc_vis_dll.h" +#include "xbmc_addon_cpp_dll.h" +#include <GL/glew.h> +#include "libprojectM/ConfigFile.h" +#include "libprojectM/projectM.hpp" +#include <string> + +projectM *globalPM = NULL; + +// some projectm globals +int maxSamples=512; +int texsize=512; +int gx=40,gy=30; +int fps=100; +char *disp; +char g_visName[512]; +char **g_presets=NULL; +unsigned int g_numPresets = 0; +projectM::Settings g_configPM; +std::string g_configFile; + +// settings vector +std::vector<DllSetting> g_vecSettings; +StructSetting** g_structSettings; +unsigned int g_uiVisElements; + +//-- Create ------------------------------------------------------------------- +// Called once when the visualisation is created by XBMC. Do any setup here. +//----------------------------------------------------------------------------- +extern "C" ADDON_STATUS Create(void* hdl, void* props) +{ + if (!props) + return STATUS_UNKNOWN; + + g_vecSettings.clear(); + g_uiVisElements = 0; + + + VIS_PROPS* visprops = (VIS_PROPS*)props; + + strcpy(g_visName, visprops->name); + g_configFile = string(visprops->profile) + string("/projectm.conf"); + std::string presetsDir = "special://xbmc/addons/visualizations/ProjectM/resources/presets.zip/"; + + g_configPM.meshX = gx; + g_configPM.meshY = gy; + g_configPM.fps = fps; + g_configPM.textureSize = texsize; + g_configPM.windowWidth = visprops->width; + g_configPM.windowHeight = visprops->height; + g_configPM.presetURL = presetsDir; + g_configPM.smoothPresetDuration = 5; + g_configPM.presetDuration = 15; + g_configPM.beatSensitivity = 10.0; + g_configPM.aspectCorrection = true; + g_configPM.easterEgg = 0.0; + g_configPM.shuffleEnabled = true; + g_configPM.windowLeft = visprops->x; + g_configPM.windowBottom = visprops->y; + + // if no config file exists, create a blank one as Config ctor throws an exception! + FILE *f; + f = fopen(g_configFile.c_str(), "r"); + if (!f) f = fopen(g_configFile.c_str(), "w"); + fclose(f); + + // save our config + try + { + projectM::writeConfig(g_configFile, g_configPM); + } + catch (...) + { + printf("exception in projectM::WriteConfig"); + return STATUS_UNKNOWN; + } + + if (globalPM) + delete globalPM; + + try + { + globalPM = new projectM(g_configFile); + } + catch (...) + { + printf("exception in projectM ctor"); + return STATUS_UNKNOWN; + } + + DllSetting quality(DllSetting::SPIN, "quality", "30000"); + quality.AddEntry("30001"); + quality.AddEntry("30002"); + quality.AddEntry("30003"); + quality.AddEntry("30004"); + if (g_configPM.textureSize == 2048) + { + quality.current = 3; + } + else if (g_configPM.textureSize == 1024) + { + quality.current = 2; + } + else if (g_configPM.textureSize == 512) + { + quality.current = 1; + } + else if (g_configPM.textureSize == 256) + { + quality.current = 0; + } + g_vecSettings.push_back(quality); + + DllSetting shuffleMode(DllSetting::CHECK, "shuffle", "30005"); + shuffleMode.current = globalPM->isShuffleEnabled(); + g_vecSettings.push_back(shuffleMode); + + DllSetting smoothPresetDuration(DllSetting::SPIN, "smooth_duration", "30006"); + for (int i=0; i < 50; i++) + { + char temp[10]; + sprintf(temp, "%i secs", i); + smoothPresetDuration.AddEntry(temp); + } + smoothPresetDuration.current = (int)(g_configPM.smoothPresetDuration); + g_vecSettings.push_back(smoothPresetDuration); + + DllSetting presetDuration(DllSetting::SPIN, "preset_duration", "30007"); + for (int i=0; i < 50; i++) + { + char temp[10]; + sprintf(temp, "%i secs", i); + presetDuration.AddEntry(temp); + } + presetDuration.current = (int)(g_configPM.presetDuration); + g_vecSettings.push_back(presetDuration); + + DllSetting beatSensitivity(DllSetting::SPIN, "beat_sens", "30008"); + for (int i=0; i <= 100; i++) + { + char temp[10]; + sprintf(temp, "%2.1f", (float)(i + 1)/5); + beatSensitivity.AddEntry(temp); + } + beatSensitivity.current = (int)(g_configPM.beatSensitivity * 5 - 1); + g_vecSettings.push_back(beatSensitivity); + + return STATUS_NEED_SETTINGS; +} + +//-- Start -------------------------------------------------------------------- +// Called when a new soundtrack is played +//----------------------------------------------------------------------------- +extern "C" void Start(int iChannels, int iSamplesPerSec, int iBitsPerSample, const char* szSongName) +{ + //printf("Got Start Command\n"); +} + +//-- Stop --------------------------------------------------------------------- +// Called when the visualisation is closed by XBMC +//----------------------------------------------------------------------------- +extern "C" void Stop() +{ + if (globalPM) + { + projectM::writeConfig(g_configFile,globalPM->settings()); + delete globalPM; + globalPM = NULL; + } + if (g_presets) + { + for (unsigned i = 0; i <g_numPresets; i++) + { + free(g_presets[i]); + } + free(g_presets); + g_presets = NULL; + } + g_numPresets = 0; +} + +//-- Audiodata ---------------------------------------------------------------- +// Called by XBMC to pass new audio data to the vis +//----------------------------------------------------------------------------- +extern "C" void AudioData(const short* pAudioData, int iAudioDataLength, float *pFreqData, int iFreqDataLength) +{ + globalPM->pcm()->addPCM16Data(pAudioData, iAudioDataLength); +} + +//-- Render ------------------------------------------------------------------- +// Called once per frame. Do all rendering here. +//----------------------------------------------------------------------------- +extern "C" void Render() +{ + globalPM->renderFrame(); +} + +//-- GetInfo ------------------------------------------------------------------ +// Tell XBMC our requirements +//----------------------------------------------------------------------------- +extern "C" void GetInfo(VIS_INFO* pInfo) +{ + pInfo->bWantsFreq = false; + pInfo->iSyncDelay = 0; +} + +//-- OnAction ----------------------------------------------------------------- +// Handle XBMC actions such as next preset, lock preset, album art changed etc +//----------------------------------------------------------------------------- +extern "C" bool OnAction(long flags, const void *param) +{ + bool ret = false; + + if (flags == VIS_ACTION_LOAD_PRESET && param) + { + int pindex = *((int *)param); + globalPM->selectPreset(pindex); + ret = true; + } + else if (flags == VIS_ACTION_NEXT_PRESET) + { +// switchPreset(ALPHA_NEXT, SOFT_CUT); + if (!globalPM->isShuffleEnabled()) + globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_n, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + else + globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + ret = true; + } + else if (flags == VIS_ACTION_PREV_PRESET) + { +// switchPreset(ALPHA_PREVIOUS, SOFT_CUT); + if (!globalPM->isShuffleEnabled()) + globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_p, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + else + globalPM->key_handler(PROJECTM_KEYDOWN, PROJECTM_K_r, PROJECTM_KMOD_CAPS); //ignore PROJECTM_KMOD_CAPS + + ret = true; + } + else if (flags == VIS_ACTION_RANDOM_PRESET) + { + globalPM->setShuffleEnabled(g_configPM.shuffleEnabled); + ret = true; + } + else if (flags == VIS_ACTION_LOCK_PRESET) + { + globalPM->setPresetLock(!globalPM->isPresetLocked()); + ret = true; + } + return ret; +} + +//-- GetPresets --------------------------------------------------------------- +// Return a list of presets to XBMC for display +//----------------------------------------------------------------------------- +extern "C" unsigned int GetPresets(char ***presets) +{ + g_numPresets = globalPM->getPlaylistSize(); + if (g_numPresets > 0) + { + g_presets = (char**) malloc(sizeof(char*)*g_numPresets); + for (unsigned i = 0; i < g_numPresets; i++) + { + g_presets[i] = (char*) malloc(strlen(globalPM->getPresetName(i).c_str())+2); + if (g_presets[i]) + strcpy(g_presets[i], globalPM->getPresetName(i).c_str()); + } + *presets = g_presets; + } + return g_numPresets; +} + +//-- GetPreset ---------------------------------------------------------------- +// Return the index of the current playing preset +//----------------------------------------------------------------------------- +extern "C" unsigned GetPreset() +{ + if (g_presets) + { + unsigned preset; + if(globalPM->selectedPresetIndex(preset)) + return preset; + } + return 0; +} + +//-- IsLocked ----------------------------------------------------------------- +// Returns true if this add-on use settings +//----------------------------------------------------------------------------- +extern "C" bool IsLocked() +{ + if(globalPM) + return globalPM->isPresetLocked(); + else + return false; +} + +//-- Remove ------------------------------------------------------------------- +// Do everything before unload of this add-on +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" void Remove() +{ +} + +//-- HasSettings -------------------------------------------------------------- +// Returns true if this add-on use settings +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" bool HasSettings() +{ + return true; +} + +//-- GetStatus --------------------------------------------------------------- +// Returns the current Status of this visualisation +// !!! Add-on master function !!! +//----------------------------------------------------------------------------- +extern "C" ADDON_STATUS GetStatus() +{ + return STATUS_OK; +} + +//-- GetSettings -------------------------------------------------------------- +// Return the settings for XBMC to display +//----------------------------------------------------------------------------- + +extern "C" unsigned int GetSettings(StructSetting ***sSet) +{ + g_uiVisElements = DllUtils::VecToStruct(g_vecSettings, &g_structSettings); + *sSet = g_structSettings; + return g_uiVisElements; +} + +//-- FreeSettings -------------------------------------------------------------- +// Free the settings struct passed from XBMC +//----------------------------------------------------------------------------- + +extern "C" void FreeSettings() +{ + DllUtils::FreeStruct(g_uiVisElements, &g_structSettings); +} + +//-- UpdateSetting ------------------------------------------------------------ +// Handle setting change request from XBMC +//----------------------------------------------------------------------------- +extern "C" ADDON_STATUS SetSetting(const char* id, const void* value) +{ + if (!id || !value) + return STATUS_UNKNOWN; + + if (strcmp(id, "quality")==0) + { + switch (*(int*) value) + { + case 0: + g_configPM.textureSize = 256; + break; + case 1: + g_configPM.textureSize = 512; + break; + case 2: + g_configPM.textureSize = 1024; + break; + case 3: + g_configPM.textureSize = 2048; + break; + } + } + else if (strcmp(id, "shuffle")==0) + { + g_configPM.shuffleEnabled = !g_configPM.shuffleEnabled; + if (globalPM) + OnAction(VIS_ACTION_RANDOM_PRESET, value); + } + else if (strcmp(id, "smooth_duration")==0) + g_configPM.smoothPresetDuration = *(int*)value; + else if (strcmp(id, "preset_duration")==0) + g_configPM.presetDuration = *(int*)value; + else if (strcmp(id, "beat_sens")==0) + g_configPM.beatSensitivity = *(int*)value; + + return STATUS_OK; +} + +//-- GetSubModules ------------------------------------------------------------ +// Return any sub modules supported by this vis +//----------------------------------------------------------------------------- +extern "C" unsigned int GetSubModules(char ***names) +{ + return 0; // this vis supports 0 sub modules +} diff --git a/xbmc/visualizations/XBMCProjectM/Makefile.in b/xbmc/visualizations/XBMCProjectM/Makefile.in index a81d771193..72d687b021 100644 --- a/xbmc/visualizations/XBMCProjectM/Makefile.in +++ b/xbmc/visualizations/XBMCProjectM/Makefile.in @@ -1,7 +1,8 @@ ARCH=@ARCH@ -INCLUDES=-I. -I.. -I../../linux -I../../ -I../../../guilib -I../../../visualisations +INCLUDES=-I. -I../../addons/include OBJS=Main.o -SLIB=../../../visualisations/ProjectM.vis +SLIB=../../../addons/visualizations/ProjectM/projectM.vis +DEFINES+=-DHAS_SDL_OPENGL -DHAS_SDL CXXFLAGS=-fPIC DIRS=libprojectM diff --git a/xbmc/visualizations/XBMCProjectM/libprojectM/Preset.cpp b/xbmc/visualizations/XBMCProjectM/libprojectM/Preset.cpp index d3ecf3cd7b..7f0874cfa2 100644 --- a/xbmc/visualizations/XBMCProjectM/libprojectM/Preset.cpp +++ b/xbmc/visualizations/XBMCProjectM/libprojectM/Preset.cpp @@ -22,6 +22,7 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> +#include <fcntl.h> #ifdef WIN32 #include "win32-dirent.h" #else @@ -35,8 +36,7 @@ #include "InitCondUtils.hpp" #include "fatal.h" #include <iostream> -#include <fstream> - +#include <sstream> Preset::Preset(std::istream & in, const std::string & presetName, PresetInputs & presetInputs, PresetOutputs & presetOutputs): builtinParams(presetInputs, presetOutputs), @@ -515,17 +515,30 @@ return PROJECTM_SUCCESS; by the given pathname */ int Preset::loadPresetFile(const std::string & pathname) { - - /* Open the file corresponding to pathname */ - std::ifstream fs(pathname.c_str()); - if (!fs || fs.eof()) { + FILE* f = fopen(pathname.c_str(), "r"); + if (!f) { if (PRESET_DEBUG) std::cerr << "loadPresetFile: loading of file \"" << pathname << "\" failed!\n"; return PROJECTM_ERROR; } - return readIn(fs); + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + rewind(f); + std::vector<char> buffer(fsize); + + int err = fread(&buffer[0], 1, fsize, f); + if (!err) + { + printf("read failed\n"); + fclose(f); + return PROJECTM_ERROR; + } + fclose(f); + std::stringstream stream; + stream.rdbuf()->pubsetbuf(&buffer[0],buffer.size()); + return readIn(stream); } diff --git a/xbmc/visualizations/iTunes/Main.cpp b/xbmc/visualizations/iTunes/Main.cpp index 602bb4537e..3ccd0f839f 100644 --- a/xbmc/visualizations/iTunes/Main.cpp +++ b/xbmc/visualizations/iTunes/Main.cpp @@ -1,5 +1,5 @@ /*
- * Copyright (C) 2005-2009 Team XBMC
+ * Copyright (C) 2005-2010 Team XBMC
* http://www.xbmc.org
*
* This Program is free software; you can redistribute it and/or modify
@@ -19,32 +19,14 @@ *
*/
-
/*
iTunes Visualization Wrapper for XBMC
*/
-
#include "xbmc_vis.h"
#include <GL/glew.h>
#include <string>
-#ifdef _WIN32
-#ifndef _MINGW
-#include "win32-dirent.h"
-#endif
-#include <io.h>
-#else
-#include "system.h"
-#include <dirent.h>
-#endif
-#ifdef _LINUX
-#include <dlfcn.h>
-#endif
-#ifdef __APPLE__
#include "itunes_vis.h"
-#endif
-
-using namespace std;
int g_tex_width = 512;
int g_tex_height = 512;
@@ -64,23 +46,23 @@ long g_tex_buffer_size = 0; ITunesVis* g_plugin = NULL;
//-- Create -------------------------------------------------------------------
-// Called once when the visualisation is created by XBMC. Do any setup here.
+// Called on load. Addon should fully initalize or return error status
//-----------------------------------------------------------------------------
-extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth,
- int iHeight, const char* szVisualisationName,
- float fPixelRatio, const char *szSubModuleName)
+ADDON_STATUS Create(void* hdl, void* visProps)
{
- if ( szVisualisationName )
- g_vis_name = szVisualisationName;
- m_vecSettings.clear();
- m_uiVisElements = 0;
+ if (!visProps)
+ return STATUS_UNKNOWN;
+
+ VIS_PROPS* props = (VIS_PROPS*) visProps;
+
+ g_vis_name = props->name;
+ g_sub_module = props->submodule;
/* copy window dimensions */
- g_window_width = g_tex_width = iWidth;
- g_window_height = g_tex_height = iHeight;
- g_window_xpos = iPosX;
- g_window_ypos = iPosY;
- g_sub_module = szSubModuleName;
+ g_window_width = g_tex_width = props->width;
+ g_window_height = g_tex_height = props->height;
+ g_window_xpos = props->x;
+ g_window_ypos = props->y
/* create texture buffer */
g_tex_buffer_size = g_tex_width * g_tex_height * 4;
@@ -116,7 +98,7 @@ extern "C" void Create(void* pd3dDevice, int iPosX, int iPosY, int iWidth, ivis_start( g_plugin );
}
- return;
+ return STATUS_OK;
}
//-- Start --------------------------------------------------------------------
@@ -148,7 +130,7 @@ extern "C" void Stop() //-- Audiodata ----------------------------------------------------------------
// Called by XBMC to pass new audio data to the vis
//-----------------------------------------------------------------------------
-extern "C" void AudioData(short* pAudioData, int iAudioDataLength,
+extern "C" void AudioData(const short* pAudioData, int iAudioDataLength,
float *pFreqData, int iFreqDataLength)
{
int copysize = iAudioDataLength < (int)sizeof( g_audio_data ) ? iAudioDataLength : (int)sizeof( g_audio_data );
@@ -270,7 +252,7 @@ extern "C" void GetInfo(VIS_INFO* pInfo) //-- OnAction -----------------------------------------------------------------
// Handle XBMC actions such as next preset, lock preset, album art changed etc
//-----------------------------------------------------------------------------
-extern "C" bool OnAction(long flags, void *param)
+extern "C" bool OnAction(long flags, const void *param)
{
bool ret = false;
@@ -308,36 +290,69 @@ extern "C" bool OnAction(long flags, void *param) //-- GetPresets ---------------------------------------------------------------
// Return a list of presets to XBMC for display
//-----------------------------------------------------------------------------
-extern "C" void GetPresets(char ***pPresets, int *currentPreset, int *numPresets,
- bool *locked)
+extern "C" unsigned int GetPresets(char ***pPresets)
{
+ return 0;
+}
+//-- GetSubModules ------------------------------------------------------------
+// Return a list of names and paths for submodules
+//-----------------------------------------------------------------------------
+extern "C" int GetSubModules(char ***names, char ***paths)
+{
+ return ivis_get_visualisations( names, paths );
+}
+
+//-- Remove -------------------------------------------------------------------
+// Do everything before unload of this add-on
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" void Remove()
+{
+}
+
+//-- HasSettings --------------------------------------------------------------
+// Returns true if this add-on use settings
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" bool HasSettings()
+{
+ return true;
+}
+
+//-- GetStatus ---------------------------------------------------------------
+// Returns the current Status of this visualisation
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+extern "C" ADDON_STATUS GetStatus()
+{
+ return STATUS_OK;
}
//-- GetSettings --------------------------------------------------------------
// Return the settings for XBMC to display
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" unsigned int GetSettings(StructSetting*** sSet)
-{
- m_uiVisElements = VisUtils::VecToStruct(m_vecSettings, &m_structSettings);
- *sSet = m_structSettings;
- return m_uiVisElements;
+extern "C" unsigned int GetSettings(StructSetting ***sSet)
+{
+ return 0;
}
+//-- FreeSettings --------------------------------------------------------------
+// Free the settings struct passed from XBMC
+// !!! Add-on master function !!!
+//-----------------------------------------------------------------------------
+
extern "C" void FreeSettings()
{
- VisUtils::FreeStruct(m_uiVisElements, &m_structSettings);
}
-//-- UpdateSetting ------------------------------------------------------------
-// Handle setting change request from XBMC
+//-- SetSetting ---------------------------------------------------------------
+// Set a specific Setting value (called from XBMC)
+// !!! Add-on master function !!!
//-----------------------------------------------------------------------------
-extern "C" void UpdateSetting(int num, StructSetting*** sSet)
+extern "C" ADDON_STATUS SetSetting(const char *strSetting, const void* value)
{
- //VisSetting &setting = m_vecSettings[num];
+ return STATUS_OK;
}
-extern "C" int GetSubModules(char ***names, char ***paths)
-{
- return ivis_get_visualisations( names, paths );
-}
diff --git a/xbmc/visualizations/iTunes/Makefile.in b/xbmc/visualizations/iTunes/Makefile.in index bf7f250e85..4d4c1c600a 100644 --- a/xbmc/visualizations/iTunes/Makefile.in +++ b/xbmc/visualizations/iTunes/Makefile.in @@ -1,8 +1,8 @@ ARCH=@ARCH@ -INCLUDES=-I. -I.. -I../../../xbmc/linux -I../../../xbmc -I../../../guilib -I../../../visualisations -I/opt/local/include +INCLUDES=-I. -I../../addons/include -I/opt/local/include OBJS=Main.o itunes_vis.o qview.o common_osx.o CXXFLAGS=-Wall -g -fPIC -SLIB=../../../visualisations/iTunes.mvis +SLIB=../../../addons/visualizations/iTunes/iTunes.mvis $(SLIB): $(OBJS) ifeq ($(findstring osx,$(ARCH)), osx) diff --git a/xbmc/win32/PlatformDefs.h b/xbmc/win32/PlatformDefs.h index c19c980ce1..93fc5544b3 100644 --- a/xbmc/win32/PlatformDefs.h +++ b/xbmc/win32/PlatformDefs.h @@ -88,6 +88,7 @@ typedef unsigned long ThreadIdentifier; #define strtoll(p, e, b) _strtoi64(p, e, b) extern "C" char * strptime(const char *buf, const char *fmt, struct tm *tm); +extern "C" int strverscmp (const char *s1, const char *s2); #endif // _WIN32 diff --git a/xbmc/win32/strverscmp.cpp b/xbmc/win32/strverscmp.cpp new file mode 100644 index 0000000000..6641e8a880 --- /dev/null +++ b/xbmc/win32/strverscmp.cpp @@ -0,0 +1,135 @@ +extern "C" {
+/* Compare strings while treating digits characters numerically.
+ Copyright (C) 1997, 2000 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Jean-Franois Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
+ fractional parts, S_Z: idem but with leading Zeroes only */
+#define S_N 0x0
+#define S_I 0x4
+#define S_F 0x8
+#define S_Z 0xC
+
+/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
+#define CMP 2
+#define LEN 3
+
+
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#undef __strverscmp
+#undef strverscmp
+
+#ifndef weak_alias
+# define __strverscmp strverscmp
+#endif
+
+/* Compare S1 and S2 as strings holding indices/version numbers,
+ returning less than, equal to or greater than zero if S1 is less than,
+ equal to or greater than S2 (for more info, see the texinfo doc).
+*/
+
+int
+__strverscmp (const char *s1, const char *s2)
+{
+ const unsigned char *p1 = (const unsigned char *) s1;
+ const unsigned char *p2 = (const unsigned char *) s2;
+ unsigned char c1, c2;
+ int state;
+ int diff;
+
+ /* Symbol(s) 0 [1-9] others (padding)
+ Transition (10) 0 (01) d (00) x (11) - */
+ static const unsigned int next_state[] =
+ {
+ /* state x d 0 - */
+ /* S_N */ S_N, S_I, S_Z, S_N,
+ /* S_I */ S_N, S_I, S_I, S_I,
+ /* S_F */ S_N, S_F, S_F, S_F,
+ /* S_Z */ S_N, S_F, S_Z, S_Z
+ };
+
+ static const int result_type[] =
+ {
+ /* state x/x x/d x/0 x/- d/x d/d d/0 d/-
+ 0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
+
+ /* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ /* S_I */ CMP, -1, -1, CMP, 1, LEN, LEN, CMP,
+ 1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
+ /* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
+ CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
+ /* S_Z */ CMP, 1, 1, CMP, -1, CMP, CMP, CMP,
+ -1, CMP, CMP, CMP
+ };
+
+ if (p1 == p2)
+ return 0;
+
+ c1 = *p1++;
+ c2 = *p2++;
+ /* Hint: '0' is a digit too. */
+ state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0));
+
+ while ((diff = c1 - c2) == 0 && c1 != '\0')
+ {
+ state = next_state[state];
+ c1 = *p1++;
+ c2 = *p2++;
+ state |= (c1 == '0') + (ISDIGIT (c1) != 0);
+ }
+
+ state = result_type[state << 2 | ((c2 == '0') + (ISDIGIT (c2) != 0))];
+
+ switch (state)
+ {
+ case CMP:
+ return diff;
+
+ case LEN:
+ while (ISDIGIT (*p1++))
+ if (!ISDIGIT (*p2++))
+ return 1;
+
+ return ISDIGIT (*p2) ? -1 : diff;
+
+ default:
+ return state;
+ }
+}
+#ifdef weak_alias
+weak_alias (__strverscmp, strverscmp)
+#endif +} |