aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjmarshallnz <jmarshallnz@svn>2010-09-10 22:53:16 +0000
committerjmarshallnz <jmarshallnz@svn>2010-09-10 22:53:16 +0000
commit112f568bcf2a5bc2220fe387e1ee7c897de3b3a5 (patch)
tree36e80cd60a0c2b9e84cd898ffac22dd8eb4ee6ce
parent7466d20b04523569cb443ae63809773a55144ce3 (diff)
merged: webinterface branch into trunk.
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@33665 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
-rw-r--r--XBMC.xcodeproj/project.pbxproj4
-rw-r--r--addons/webinterface.default/css/core.css334
-rw-r--r--addons/webinterface.default/images/ajax-loader.gifbin0 -> 4782 bytes
-rw-r--r--addons/webinterface.default/images/close-button.pngbin0 -> 2531 bytes
-rw-r--r--addons/webinterface.default/images/header-selected-bg.pngbin0 -> 991 bytes
-rw-r--r--addons/webinterface.default/images/logo.pngbin22378 -> 8789 bytes
-rw-r--r--addons/webinterface.default/images/play-icon.pngbin0 -> 8561 bytes
-rw-r--r--addons/webinterface.default/images/subheader-selected-bg.pngbin0 -> 968 bytes
-rw-r--r--addons/webinterface.default/images/top-fade.pngbin0 -> 958 bytes
-rw-r--r--addons/webinterface.default/index.html38
-rw-r--r--addons/webinterface.default/js/Launcher.js43
-rw-r--r--addons/webinterface.default/js/MediaLibrary.js221
-rw-r--r--addons/webinterface.default/js/NowPlayingManager.js33
-rwxr-xr-xtools/Linux/packaging/debian/rules.hardy2
-rw-r--r--xbmc/ApplicationMessenger.cpp12
-rw-r--r--xbmc/ApplicationMessenger.h2
-rw-r--r--xbmc/DateTime.cpp32
-rw-r--r--xbmc/DateTime.h2
-rw-r--r--xbmc/FileSystem/MusicDatabaseDirectory/DirectoryNodeAlbum.cpp2
-rw-r--r--xbmc/GUIDialogSmartPlaylistRule.cpp2
-rw-r--r--xbmc/MusicDatabase.cpp17
-rw-r--r--xbmc/MusicDatabase.h2
-rw-r--r--xbmc/MusicInfoScanner.cpp2
-rw-r--r--xbmc/PlayListPlayer.cpp21
-rw-r--r--xbmc/PlayListPlayer.h2
-rw-r--r--xbmc/lib/libjsonrpc/AVPlaylistOperations.cpp8
-rw-r--r--xbmc/lib/libjsonrpc/AudioLibrary.cpp4
-rw-r--r--xbmc/lib/libjsonrpc/JSONRPC.cpp1
-rw-r--r--xbmc/utils/WebServer.cpp29
29 files changed, 613 insertions, 200 deletions
diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
index f6a05cddb3..df56146179 100644
--- a/XBMC.xcodeproj/project.pbxproj
+++ b/XBMC.xcodeproj/project.pbxproj
@@ -7204,7 +7204,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
- shellScript = "#!/bin/bash\n\necho \"copy root files\"\n\nif [ \"$ACTION\" = build ] ; then\n\n# for external testing\n#TARGET_NAME=XBMC.app\n#SRCROOT=/Users/Shared/xbmc_svn/XBMC\n#TARGET_BUILD_DIR=/Users/Shared/xbmc_svn/XBMC/build/Debug\n\n# Force TARGET_NAME on ppc (do not use XBMC_ppc.app)\nTARGET_NAME=XBMC.app\n\n# rsync command with exclusions for items we don't want in the app package\nSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.zlib --exclude *.a\"\n\n# rsync command for excluding pngs and jpgs as well. Note that if the skin itself is not compiled\n# using XBMCTex then excluding the pngs and jpgs will most likely make the skin unusable \nSYNCSKIN=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.png --exclude *.jpg --exclude *.bat\"\n\n# rsync command for including everything but the skins\nADDONSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude skin.confluence\"\n\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/language\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/sounds\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/system\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/userdata\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools/osx\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\n\n${SYNC} \"$SRCROOT/LICENSE.GPL\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/xbmc/osx/Credits.html\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/tools/osx\"\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools\"\n${ADDONSYNC} \"$SRCROOT/addons\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/language\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/media\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNCSKIN} \"$SRCROOT/addons/skin.confluence\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/backgrounds\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/icon.png\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/sounds\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/system\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/userdata\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/web/poc_jsonrpc/\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\n\n# copy extra packages if applicable\nif [ -d \"$SRCROOT/extras/system\" ]; then\n\t${SYNC} \"$SRCROOT/extras/system/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nfi\n\n# copy extra user packages if applicable\nif [ -d \"$SRCROOT/extras/user\" ]; then\n\t${SYNC} \"$SRCROOT/extras/user/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\nfi\n\n\n\n# magic that gets the icon to update\ntouch \"$TARGET_BUILD_DIR/$TARGET_NAME\"\n\n# not sure we want to do this with out major testing, many scripts cannot handle the spaces in the app name\n#mv \"$TARGET_BUILD_DIR/$TARGET_NAME\" \"$TARGET_BUILD_DIR/XBMC Media Center.app\"\n\nfi";
+ shellScript = "#!/bin/bash\n\necho \"copy root files\"\n\nif [ \"$ACTION\" = build ] ; then\n\n# for external testing\n#TARGET_NAME=XBMC.app\n#SRCROOT=/Users/Shared/xbmc_svn/XBMC\n#TARGET_BUILD_DIR=/Users/Shared/xbmc_svn/XBMC/build/Debug\n\n# Force TARGET_NAME on ppc (do not use XBMC_ppc.app)\nTARGET_NAME=XBMC.app\n\n# rsync command with exclusions for items we don't want in the app package\nSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.zlib --exclude *.a\"\n\n# rsync command for excluding pngs and jpgs as well. Note that if the skin itself is not compiled\n# using XBMCTex then excluding the pngs and jpgs will most likely make the skin unusable \nSYNCSKIN=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.png --exclude *.jpg --exclude *.bat\"\n\n# rsync command for including everything but the skins\nADDONSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude skin.confluence\"\n\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/language\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/sounds\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/system\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/userdata\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools/osx\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\n\n${SYNC} \"$SRCROOT/LICENSE.GPL\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/xbmc/osx/Credits.html\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/tools/osx\"\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools\"\n${ADDONSYNC} \"$SRCROOT/addons\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/language\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/media\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNCSKIN} \"$SRCROOT/addons/skin.confluence\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/backgrounds\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/icon.png\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/sounds\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/system\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/userdata\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/web/\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\n\n# copy extra packages if applicable\nif [ -d \"$SRCROOT/extras/system\" ]; then\n\t${SYNC} \"$SRCROOT/extras/system/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nfi\n\n# copy extra user packages if applicable\nif [ -d \"$SRCROOT/extras/user\" ]; then\n\t${SYNC} \"$SRCROOT/extras/user/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\nfi\n\n\n\n# magic that gets the icon to update\ntouch \"$TARGET_BUILD_DIR/$TARGET_NAME\"\n\n# not sure we want to do this with out major testing, many scripts cannot handle the spaces in the app name\n#mv \"$TARGET_BUILD_DIR/$TARGET_NAME\" \"$TARGET_BUILD_DIR/XBMC Media Center.app\"\n\nfi";
};
F5A1CBDF0F6B0B4700A96ABD /* copy frameworks */ = {
isa = PBXShellScriptBuildPhase;
@@ -7247,7 +7247,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/bash;
- shellScript = "#!/bin/bash\n\necho \"copy root files\"\n\nif [ \"$ACTION\" = build ] ; then\n\n# for external testing\n#TARGET_NAME=XBMC.app\n#SRCROOT=/Users/Shared/xbmc_svn/XBMC\n#TARGET_BUILD_DIR=/Users/Shared/xbmc_svn/XBMC/build/Debug\n\n# rsync command with exclusions for items we don't want in the app package\nSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.zlib --exclude *.a\"\n\n# rsync command for excluding pngs and jpgs as well. Note that if the skin itself is not compiled\n# using XBMCTex then excluding the pngs and jpgs will most likely make the skin unusable \nSYNCSKIN=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.png --exclude *.jpg --exclude *.bat\"\n\n# rsync command for including everything but the skins\nADDONSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude skin.confluence\"\n\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/language\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/sounds\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/system\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/userdata\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools/osx\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\n\n${SYNC} \"$SRCROOT/LICENSE.GPL\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/xbmc/osx/Credits.html\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/tools/osx\"\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools\"\n${ADDONSYNC} \"$SRCROOT/addons\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/language\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/media\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNCSKIN} \"$SRCROOT/addons/skin.confluence\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/backgrounds\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/icon.png\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/sounds\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/system\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/userdata\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/web/poc_jsonrpc/\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\n\n# copy extra packages if applicable\nif [ -d \"$SRCROOT/extras/system\" ]; then\n\t${SYNC} \"$SRCROOT/extras/system/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nfi\n\n# copy extra user packages if applicable\nif [ -d \"$SRCROOT/extras/user\" ]; then\n\t${SYNC} \"$SRCROOT/extras/user/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\nfi\n\n\n\n# magic that gets the icon to update\ntouch \"$TARGET_BUILD_DIR/$TARGET_NAME\"\n\n# not sure we want to do this with out major testing, many scripts cannot handle the spaces in the app name\n#mv \"$TARGET_BUILD_DIR/$TARGET_NAME\" \"$TARGET_BUILD_DIR/XBMC Media Center.app\"\n\nfi";
+ shellScript = "#!/bin/bash\n\necho \"copy root files\"\n\nif [ \"$ACTION\" = build ] ; then\n\n# for external testing\n#TARGET_NAME=XBMC.app\n#SRCROOT=/Users/Shared/xbmc_svn/XBMC\n#TARGET_BUILD_DIR=/Users/Shared/xbmc_svn/XBMC/build/Debug\n\n# rsync command with exclusions for items we don't want in the app package\nSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.zlib --exclude *.a\"\n\n# rsync command for excluding pngs and jpgs as well. Note that if the skin itself is not compiled\n# using XBMCTex then excluding the pngs and jpgs will most likely make the skin unusable \nSYNCSKIN=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude *.dll --exclude *.DLL --exclude *linux.* --exclude *.png --exclude *.jpg --exclude *.bat\"\n\n# rsync command for including everything but the skins\nADDONSYNC=\"rsync -av --exclude CVS* --exclude .svn* --exclude .cvsignore* --exclude .cvspass* --exclude .DS_Store* --exclude skin.confluence\"\n\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/language\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/sounds\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/system\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/userdata\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/media\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools/osx\"\nmkdir -p \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\n\n${SYNC} \"$SRCROOT/LICENSE.GPL\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/xbmc/osx/Credits.html\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/\"\n${SYNC} \"$SRCROOT/tools/osx\"\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/tools\"\n${ADDONSYNC} \"$SRCROOT/addons\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/language\"\t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/media\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNCSKIN} \"$SRCROOT/addons/skin.confluence\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/backgrounds\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/addons/skin.confluence/icon.png\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/addons/skin.confluence\"\n${SYNC} \"$SRCROOT/sounds\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/system\" \t\t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/userdata\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\n${SYNC} \"$SRCROOT/web/\" \t\"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/web\"\n\n# copy extra packages if applicable\nif [ -d \"$SRCROOT/extras/system\" ]; then\n\t${SYNC} \"$SRCROOT/extras/system/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC\"\nfi\n\n# copy extra user packages if applicable\nif [ -d \"$SRCROOT/extras/user\" ]; then\n\t${SYNC} \"$SRCROOT/extras/user/\" \"$TARGET_BUILD_DIR/$TARGET_NAME/Contents/Resources/XBMC/extras/user\"\nfi\n\n\n\n# magic that gets the icon to update\ntouch \"$TARGET_BUILD_DIR/$TARGET_NAME\"\n\n# not sure we want to do this with out major testing, many scripts cannot handle the spaces in the app name\n#mv \"$TARGET_BUILD_DIR/$TARGET_NAME\" \"$TARGET_BUILD_DIR/XBMC Media Center.app\"\n\nfi";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
diff --git a/addons/webinterface.default/css/core.css b/addons/webinterface.default/css/core.css
index 7dcbdf23b8..d276f8408b 100644
--- a/addons/webinterface.default/css/core.css
+++ b/addons/webinterface.default/css/core.css
@@ -6,23 +6,251 @@ body {
#header {
position: relative;
- height: 150px;
- background: #333;
+ height: 50px;
+ border-bottom: 1px solid #000;
}
#header .logo {
+ padding-top: 1px;
+ }
+
+#navigation {
+ float: right;
+ }
+
+#spinner {
+ float: right;
+ padding: 11px 10px;
+ }
+
+#navigation ul {
+ list-style-type: none;
+ border-right: 1px solid #969696;
+ margin: 0;
+ padding: 0;
+ }
+
+#navigation ul li {
+ float: left;
+ color: #000;
+ cursor: pointer;
+ line-height: 50px;
+ margin: 0;
+ padding: 0 24px;
+ border-left: 1px solid #969696;
+ font-family: Verdana, sans-serif;
+ font-size: 18px;
+ font-weight: 700;
+ }
+
+#navigation ul li.selected,
+#navigation ul li:hover {
+ background: url('/images/header-selected-bg.png') repeat-x;
+ color: #fff;
+ }
+
+.floatableAlbum {
+ float: left;
+ width: 130px;
+ height: 150px;
padding: 10px;
- height: 100px;
}
-#nowPlayingPanel {
- background: #333;
- width: 480px;
+.floatableMovieCover {
+ float: left;
+ width: 130px;
+ height: 200px;
+ padding: 10px;
+ }
+
+.floatableTVShowCover {
+ float: left;
+ padding: 10px;
+ width: 379px;
+ height: 70px;
+ }
+
+#libraryContainer .floatableAlbum,
+#movieLibraryContainer .floatableMovieCover,
+#tvshowLibraryContainer .floatableTVShowCover {
+ cursor: pointer;
+ }
+
+.floatableAlbum div.imgWrapper,
+.floatableMovieCover div.imgWrapper,
+.floatableTVShowCover div.imgWrapper {
+ width: 130px;
height: 130px;
+ display: table-cell;
+ vertical-align: middle;
+ text-align: center;
+ }
+
+div.imgWrapper div.inner {
+ overflow: hidden;
+ width: 130px;
+ }
+
+.floatableMovieCover div.imgWrapper,
+.floatableMovieCover div.imgWrapper div.inner {
+ height: 190px;
+ }
+
+#overlay {
+ top: 50px;
+ left: 0;
+ right: 0;
+ bottom: 150px;
+ background: #3f3f3f;
+ position: fixed;
+ opacity: 0.8;
+ z-index: 2000; /* Above contentContainer's */
+ }
+
+.floatableTVShowCover div.imgWrapper,
+.floatableTVShowCover img,
+.floatableTVShowCover div.imgWrapper div.inner {
+ height: 70px;
+ width: 379px;
+ }
+
+.floatableAlbum img {
+ width: 130px;
+ }
+
+.floatableMovieCover img {
+ height: 180px;
+ }
+
+.floatableAlbum p.album,
+.floatableMovieCover p.album {
+ font-size: 12px;
+ font-weight: 700;
+ color: #000;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ width: 130px;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+.floatableAlbum p.artist,
+.floatableMovieCover p.artist {
+ font-size: 11px;
+ color: #777;
+ text-align: center;
+ margin: 0;
+ padding: 0;
+ }
+
+.contentContainer {
+ overflow-x: hidden;
+ overflow-y: auto;
+ position: absolute;
+ top: 51px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: #fff;
+ padding-bottom: 150px;
+ }
+
+.albumView .track {
+ cursor: pointer;
+ line-height: 10px;
+ font-size: 14px;
+ padding: 1px 0;
+ }
+
+/* Movie Overlay */
+
+.moviePopoverContainer {
+ z-index: 3000; /* Above overlay */
+ border: 1px solid #000;
padding: 10px;
+ margin: 10px;
+ position: fixed;
+ background: #3f3f3f;
+ top: 50px;
+ bottom: 150px;
+ left: 10%;
+ right: 10%;
+ opacity: 0.9;
+ }
+
+.moviePopoverContainer .closeButton {
+ float: right;
+ cursor: pointer;
+ }
+
+.moviePopoverContainer .movieCover {
+ height: 100%;
+ padding-right: 20px;
+ float: left;
+ z-index: 3100;
+ }
+
+.moviePopoverContainer .movieTitle {
+ font-size: 24px;
+ font-weight: 700;
+ color: #fff;
+ margin: 0;
+ }
+
+.moviePopoverContainer .runtime,
+.moviePopoverContainer .director,
+.moviePopoverContainer .genre,
+.moviePopoverContainer .plot {
+ color: #fff;
+ }
+
+.movieTitle .year {
+ font-weight: 400;
+ font-size: 18px;
+ }
+
+.playIcon {
+ background: url('/images/play-icon.png') center center no-repeat;
position: absolute;
- top: 0px;
- right: 0px;
+ z-index: 3500;
+ cursor: pointer;
+ opacity: 0.8;
+ }
+
+.playIcon:hover {
+ opacity: 1;
+ }
+
+/* Effects */
+
+#topScrollFade {
+ position: fixed;
+ top: 51px;
+ height: 33px;
+ z-index: 101;
+ left: 0;
+ right: 0;
+ background: url('/images/top-fade.png') top left repeat-x;
+ }
+
+/* Now Playing */
+
+#footerPopover {
+ position: fixed;
+ height: 150px;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ z-index: 10000; /* Top most always */
+ background: #333;
+ opacity: 0.98;
+ }
+
+#nowPlayingPanel {
+ height: 130px;
+ width: 480px;
+ padding: 10px;
}
#audioCoverArt img {
@@ -119,6 +347,7 @@ body {
width: 416px;
float: right;
cursor: pointer;
+ z-index: 1000;
}
#nowPlayingPlaylist {
@@ -244,91 +473,4 @@ body {
#pbNext:hover {
background: url('/images/OSDNextTrackFO.png') no-repeat;
- }
-
-#navigation {
- position: absolute;
- top: 100px;
- left: 0;
- }
-
-#navigation ul {
- list-style-type: none;
- }
-
-#navigation ul li {
- float: left;
- background: #ccc;
- color: #fff;
- cursor: pointer;
- border: 2px solid #333;
- margin: 2px;
- padding: 4px;
- }
-
-#navigation ul li.selected,
-#navigation ul li:hover {
- background: #aaa;
- color: #333;
- }
-
-.floatableAlbum {
- float: left;
- width: 130px;
- height: 150px;
- padding: 10px;
- }
-
-#libraryContainer .floatableAlbum {
- cursor: pointer;
- }
-
-.floatableAlbum div.imgWrapper {
- width: 130px;
- height: 130px;
- display: table-cell;
- vertical-align: middle;
- }
-
-.floatableAlbum img {
- width: 130px;
- }
-
-.floatableAlbum p.album {
- font-size: 12px;
- font-weight: 700;
- color: #000;
- text-align: center;
- margin: 0;
- padding: 0;
- width: 130px;
- white-space: nowrap;
- overflow: hidden;
- }
-
-.floatableAlbum p.artist {
- font-size: 11px;
- color: #777;
- text-align: center;
- margin: 0;
- padding: 0;
- }
-
-.contentContainer {
- overflow-x: hidden;
- overflow-y: auto;
- position: absolute;
- top: 150px;
- bottom: 0;
- left: 0;
- right: 0;
- background: #fff;
- }
-
-.albumView .track {
- cursor: pointer;
- line-height: 10px;
- font-size: 14px;
- padding: 1px 0;
- }
-
+ } \ No newline at end of file
diff --git a/addons/webinterface.default/images/ajax-loader.gif b/addons/webinterface.default/images/ajax-loader.gif
new file mode 100644
index 0000000000..4fb7c23522
--- /dev/null
+++ b/addons/webinterface.default/images/ajax-loader.gif
Binary files differ
diff --git a/addons/webinterface.default/images/close-button.png b/addons/webinterface.default/images/close-button.png
new file mode 100644
index 0000000000..767727a701
--- /dev/null
+++ b/addons/webinterface.default/images/close-button.png
Binary files differ
diff --git a/addons/webinterface.default/images/header-selected-bg.png b/addons/webinterface.default/images/header-selected-bg.png
new file mode 100644
index 0000000000..b60d4aed0b
--- /dev/null
+++ b/addons/webinterface.default/images/header-selected-bg.png
Binary files differ
diff --git a/addons/webinterface.default/images/logo.png b/addons/webinterface.default/images/logo.png
index 8001cdb2f6..0f1b681877 100644
--- a/addons/webinterface.default/images/logo.png
+++ b/addons/webinterface.default/images/logo.png
Binary files differ
diff --git a/addons/webinterface.default/images/play-icon.png b/addons/webinterface.default/images/play-icon.png
new file mode 100644
index 0000000000..e75fa97be2
--- /dev/null
+++ b/addons/webinterface.default/images/play-icon.png
Binary files differ
diff --git a/addons/webinterface.default/images/subheader-selected-bg.png b/addons/webinterface.default/images/subheader-selected-bg.png
new file mode 100644
index 0000000000..83725c9f2c
--- /dev/null
+++ b/addons/webinterface.default/images/subheader-selected-bg.png
Binary files differ
diff --git a/addons/webinterface.default/images/top-fade.png b/addons/webinterface.default/images/top-fade.png
new file mode 100644
index 0000000000..21cc82bb1a
--- /dev/null
+++ b/addons/webinterface.default/images/top-fade.png
Binary files differ
diff --git a/addons/webinterface.default/index.html b/addons/webinterface.default/index.html
index 8dfa157b28..c4690a36e5 100644
--- a/addons/webinterface.default/index.html
+++ b/addons/webinterface.default/index.html
@@ -9,13 +9,30 @@
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
<!-- <link href="/images/logo.png" rel="image_src" /> -->
<meta name="robots" content="NOINDEX, NOFOLLOW">
- <link href="/css/core.css" rel="stylesheet" type="text/css">
+ <link href="/css/core.css?1.1.0" rel="stylesheet" type="text/css">
<script type="text/javascript" src="/js/jquery-1.4.2.js"></script>
<script type="text/javascript" src="/js/Launcher.js?1.0.0"></script>
</head>
<body>
<div id="header">
<img src="/images/logo.png" alt="XBMC Logo" class="logo">
+ <div id="navigation">
+ <ul>
+ <li id="remoteControl">Remote</li>
+ <li id="movieLibrary">Movies</li>
+ <li id="tvshowLibrary">TV Shows</li>
+ <li id="musicLibrary">Music</li>
+ <li id="settingsPanel">Settings</li>
+ </ul>
+ </div>
+ <img src="/images/ajax-loader.gif" alt="Loading please wait" id="spinner" style="display: none">
+ </div>
+ <div id="body">
+ <div id="topScrollFade" style="display: none;"></div>
+ <div id="content"></div>
+ <div id="overlay" style="display: none;"></div>
+ </div>
+ <div id="footerPopover">
<div id="nowPlayingPanel" style="display: none;">
<div id="nowPlayingContent">
<div id="audioDescription">
@@ -48,23 +65,8 @@
</div>
</div>
<span id="nextText">Next:</span>
- <div id="nextTrack" style="display: none;">
-
- </div>
- <div id="nowPlayingPlaylist" style="display: none;">
-
- </div>
- </div>
- </div>
- <div id="body">
- <div id="navigation">
- <ul>
- <li id="musicLibrary">Music</li>
- <li id="videoLibrary">Videos</li>
- </ul>
- </div>
- <div id="content">
-
+ <div id="nextTrack" style="display: none;"></div>
+ <div id="nowPlayingPlaylist" style="display: none;"></div>
</div>
</div>
<script type="text/javascript">
diff --git a/addons/webinterface.default/js/Launcher.js b/addons/webinterface.default/js/Launcher.js
index 07a984c3b3..9751704f23 100644
--- a/addons/webinterface.default/js/Launcher.js
+++ b/addons/webinterface.default/js/Launcher.js
@@ -44,33 +44,38 @@
//
// For details, see the script.aculo.us web site: http://script.aculo.us/
+var DEBUG_MODE = true; /* Set to false to enable cached javascript */
+
var Launcher = {
VERSION: '1.0.0',
REQUIRED_JQUERY: '1.4.2',
load: function(libraryName) {
- document.write('<script type="text/javascript" src="' + libraryName + '?' + this.VERSION + '"><\/script>');
+ document.write('<script type="text/javascript" src="' + libraryName + '?' + (DEBUG_MODE ? this.randomValue() : this.VERSION) + '"><\/script>');
},
init: function() {
- function convertVersionString(versionString) {
- var v = versionString.replace(/_.*|\./g, '');
- v = parseInt(v + (v.length == 4 ? '' : '0'));
- return versionString.indexOf('_') > -1 ? v-1 : v;
- }
+ function convertVersionString(versionString) {
+ var v = versionString.replace(/_.*|\./g, '');
+ v = parseInt(v + (v.length == 4 ? '' : '0'));
+ return versionString.indexOf('_') > -1 ? v-1 : v;
+ }
- if(!jQuery || (convertVersionString(jQuery.fn.jquery) < convertVersionString(Launcher.REQUIRED_JQUERY)))
- throw("XBMC Web Interface requires the jQuery JavaScript framework >= " + Launcher.REQUIRED_JQUERY);
+ if(!jQuery || (convertVersionString(jQuery.fn.jquery) < convertVersionString(Launcher.REQUIRED_JQUERY)))
+ throw("XBMC Web Interface requires the jQuery JavaScript framework >= " + Launcher.REQUIRED_JQUERY);
- var js = /Launcher\.js(\?.*)?$/;
- $('html').find('script[src]').each(
- function(i, s) {
- if (s.src.match(js)) {
- var path = s.src.replace(js, ''),
- includes = s.src.match(/\?.*load=([a-z,]*)/);
- $.each((includes ? includes[1] : 'jquery.lazyload,Core,MediaLibrary,NowPlayingManager').split(','), function(i, include) {
- Launcher.load(path + include + '.js')
- });
- }
- });
+ var js = /Launcher\.js(\?.*)?$/;
+ $('html').find('script[src]').each(
+ function(i, s) {
+ if (s.src.match(js)) {
+ var path = s.src.replace(js, ''),
+ includes = s.src.match(/\?.*load=([a-z,]*)/);
+ $.each((includes ? includes[1] : 'jquery.lazyload,Core,MediaLibrary,NowPlayingManager').split(','), function(i, include) {
+ Launcher.load(path + include + '.js')
+ });
+ }
+ });
+ },
+ randomValue: function() {
+ return Math.random();
}
}
diff --git a/addons/webinterface.default/js/MediaLibrary.js b/addons/webinterface.default/js/MediaLibrary.js
index c3375b21ae..20e0e0af66 100644
--- a/addons/webinterface.default/js/MediaLibrary.js
+++ b/addons/webinterface.default/js/MediaLibrary.js
@@ -30,14 +30,24 @@ MediaLibrary.prototype = {
},
bindControls: function() {
$('#musicLibrary').click(jQuery.proxy(this.musicLibraryOpen, this));
- $('#videoLibrary').click(jQuery.proxy(this.videoLibraryOpen, this));
+ $('#movieLibrary').click(jQuery.proxy(this.movieLibraryOpen, this));
+ $('#tvshowLibrary').click(jQuery.proxy(this.tvshowLibraryOpen, this));
+ $('#overlay').click(jQuery.proxy(this.hideOverlay, this));
+ $(window).resize(jQuery.proxy(this.updatePlayButtonLocation, this));
+ },
+ resetPage: function() {
+ $('#musicLibrary').removeClass('selected');
+ $('#movieLibrary').removeClass('selected');
+ $('#tvshowLibrary').removeClass('selected');
+ this.hideOverlay();
},
musicLibraryOpen: function(event) {
+ this.resetPage();
$('#musicLibrary').addClass('selected');
- $('#videoLibrary').removeClass('selected');
$('.contentContainer').css('z-index', 1);
var libraryContainer = $('#libraryContainer');
if (!libraryContainer || libraryContainer.length == 0) {
+ $('#spinner').show();
jQuery.post(JSON_RPC + '?GetAlbums', '{"jsonrpc": "2.0", "method": "AudioLibrary.GetAlbums", "params": { "start": 0, "fields": ["album_description", "album_theme", "album_mood", "album_style", "album_type", "album_label", "album_artist", "album_genre", "album_rating", "album_title"] }, "id": 1}', jQuery.proxy(function(data) {
if (data && data.result && data.result.albums) {
libraryContainer = $('<div>');
@@ -49,19 +59,26 @@ MediaLibrary.prototype = {
libraryContainer.html('');
}
$.each($(data.result.albums), jQuery.proxy(function(i, item) {
- var floatableAlbum = this.generateAlbumThumb(item.thumbnail, item.album_title, item.album_artist);
- floatableAlbum.bind('click', {album: item, }, jQuery.proxy(this.displayAlbumDetails, this));
+ var floatableAlbum = this.generateThumb('album', item.thumbnail, item.album_title, item.album_artist);
+ floatableAlbum.bind('click', { album: item }, jQuery.proxy(this.displayAlbumDetails, this));
libraryContainer.append(floatableAlbum);
}, this));
+ $('#spinner').hide();
//$('#libraryContainer img').lazyload();
+ libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
+ libraryContainer.trigger('scroll');
}, this), 'json');
} else {
libraryContainer.css('z-index', 100);
+ libraryContainer.trigger('scroll');
}
},
- generateAlbumThumb: function(thumbnail, album_title, album_artist) {
+ getThumbnailPath: function(thumbnail) {
+ return thumbnail ? ('/vfs/' + thumbnail) : DEFAULT_ALBUM_COVER;
+ },
+ generateThumb: function(type, thumbnail, album_title, album_artist) {
var floatableAlbum = $('<div>');
- var path = thumbnail ? ('/vfs/' + thumbnail) : DEFAULT_ALBUM_COVER;
+ var path = this.getThumbnailPath(thumbnail);
var title = album_title;
var artist = album_artist;
if (title.length > 18 && !(title.length <= 21)) {
@@ -70,14 +87,29 @@ MediaLibrary.prototype = {
if (artist.length > 20 && !(artist.length <= 22)) {
artist = album_artist.substring(0, 20) + '...';
}
- floatableAlbum.addClass('floatableAlbum')
- .html('<div class="imgWrapper"><img src="' + path + '" alt="" /></div><p class="album" title="' + album_title + '">' + title + '</p><p class="artist" title="' + album_artist + '">' + artist + '</p>');
- return floatableAlbum
+ var className = '';
+ var code = '';
+ switch(type) {
+ case 'album':
+ className = 'floatableAlbum';
+ code = '<p class="album" title="' + album_title + '">' + title + '</p><p class="artist" title="' + album_artist + '">' + artist + '</p>';
+ break;
+ case 'movie':
+ className = 'floatableMovieCover';
+ code = '<p class="album" title="' + album_title + '">' + title + '</p>';
+ break;
+ case 'tvshow':
+ className = 'floatableTVShowCover';
+ break;
+ }
+ floatableAlbum.addClass(className).html('<div class="imgWrapper"><div class="inner"><img src="' + path + '" alt="" /></div></div>' + code);
+ return floatableAlbum;
},
displayAlbumDetails: function(event) {
-
var albumDetailsContainer = $('#albumDetails' + event.data.album.albumid);
+ $('#topScrollFade').hide();
if (!albumDetailsContainer || albumDetailsContainer.length == 0) {
+ $('#spinner').show();
jQuery.post(JSON_RPC + '?GetSongs', '{"jsonrpc": "2.0", "method": "AudioLibrary.GetSongs", "params": { "fields": ["title", "artist", "genre", "tracknumber", "discnumber", "duration", "year"], "albumid" : ' + event.data.album.albumid + ' }, "id": 1}', jQuery.proxy(function(data) {
albumDetailsContainer = $('<div>');
albumDetailsContainer.attr('id', 'albumDetails' + event.data.album.albumid)
@@ -97,19 +129,19 @@ MediaLibrary.prototype = {
trackRow.append(albumTD);
}
var trackNumberTD = $('<td>');
- trackNumberTD.html(item.tracknumber).addClass('track').bind('click', { song: item }, jQuery.proxy(this.playTrack, this));
+ trackNumberTD.html(item.tracknumber).addClass('track').bind('click', { song: item, album: event.data.album }, jQuery.proxy(this.playTrack, this));
trackRow.append(trackNumberTD);
var trackTitleTD = $('<td>');
- trackTitleTD.html(item.title).addClass('track').bind('click', { song: item }, jQuery.proxy(this.playTrack, this));
+ trackTitleTD.html(item.title).addClass('track').bind('click', { song: item, album: event.data.album }, jQuery.proxy(this.playTrack, this));
trackRow.append(trackTitleTD);
var trackDurationTD = $('<td>');
- trackDurationTD.html(durationToString(item.duration)).addClass('track').bind('click', { song: item }, jQuery.proxy(this.playTrack, this));
+ trackDurationTD.html(durationToString(item.duration)).addClass('track').bind('click', { song: item, album: event.data.album }, jQuery.proxy(this.playTrack, this));
trackRow.append(trackDurationTD);
var trackArtistTD = $('<td>');
- trackArtistTD.html(item.artist).addClass('track').bind('click', { song: item }, jQuery.proxy(this.playTrack, this));
+ trackArtistTD.html(item.artist).addClass('track').bind('click', { song: item, album: event.data.album }, jQuery.proxy(this.playTrack, this));
trackRow.append(trackArtistTD);
var trackGenreTD = $('<td>');
- trackGenreTD.html(item.genre).addClass('track').bind('click', { song: item }, jQuery.proxy(this.playTrack, this));
+ trackGenreTD.html(item.genre).addClass('track').bind('click', { song: item, album: event.data.album }, jQuery.proxy(this.playTrack, this));
trackRow.append(trackGenreTD);
$('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow);
}, this));
@@ -132,22 +164,167 @@ MediaLibrary.prototype = {
trackRow.append(trackGenreTD);
$('#albumDetails' + event.data.album.albumid + ' .resultSet').append(trackRow);
}
- $('#albumDetails' + event.data.album.albumid + ' .albumThumb').append(this.generateAlbumThumb(albumThumbnail, albumTitle, albumArtist));
+ $('#albumDetails' + event.data.album.albumid + ' .albumThumb').append(this.generateThumb('album', albumThumbnail, albumTitle, albumArtist));
$('.contentContainer').css('z-index', 1);
+ $('#spinner').hide();
}, this), 'json');
} else {
$('.contentContainer').css('z-index', 1);
$('#albumDetails' + event.data.album.albumid).css('z-index', 100);
}
},
- playTrack: function(event) {
- jQuery.post(JSON_RPC + '?PlaySong', '{"jsonrpc": "2.0", "method": "XBMC.Play", "params": { "songid": ' + event.data.song.songid + ' }, "id": 1}', jQuery.proxy(function(data) {
+ hideOverlay: function(event) {
+ if (this.activeCover) {
+ $(this.activeCover).remove();
+ this.activeCover = null;
+ }
+ $('#overlay').hide();
+ },
+ updatePlayButtonLocation: function(event) {
+ var movieContainer = $('.movieCover');
+ if (movieContainer.length > 0) {
+ var playIcon = $('.playIcon');
+ if (playIcon.length > 0) {
+ playIcon.width($(movieContainer[0]).width());
+ playIcon.height($(movieContainer[0]).height());
+ }
+ }
+ },
+ playMovie: function(event) {
+ jQuery.post(JSON_RPC + '?PlayMovie', '{"jsonrpc": "2.0", "method": "XBMC.Play", "params": { "movieid": ' + event.data.movie.movieid + ' }, "id": 1}', jQuery.proxy(function(data) {
+
+ this.hideOverlay();
+ }, this), 'json');
+ },
+ displayMovieDetails: function(event) {
+ var movieDetails = $('<div>');
+ movieDetails.attr('id', 'movie-' + event.data.movie.movieid);
+ movieDetails.addClass('moviePopoverContainer');
+ var closeButton = $('<img>');
+ closeButton.attr('src', '/images/close-button.png');
+ closeButton.addClass('closeButton').bind('click', jQuery.proxy(this.hideOverlay, this));
+ movieDetails.append(closeButton);
+ var movieCover = $('<img>');
+ movieCover.attr('src', this.getThumbnailPath(event.data.movie.thumbnail)).addClass('movieCover');
+ movieDetails.append(movieCover);
+ var playIcon = $('<div>');
+ playIcon.addClass('playIcon');
+ playIcon.bind('click', {movie: event.data.movie}, jQuery.proxy(this.playMovie, this));
+ movieDetails.append(playIcon);
+ var movieTitle = $('<p>');
+ movieTitle.addClass('movieTitle');
+ var yearText = event.data.movie.year ? ' <span class="year">(' + event.data.movie.year + ')</span>' : '';
+ movieTitle.html(event.data.movie.title + yearText);
+ movieDetails.append(movieTitle);
+ if (event.data.movie.runtime) {
+ var runtime = $('<p>');
+ runtime.addClass('runtime').html('<strong>Runtime:</strong> ' + event.data.movie.runtime + ' minutes');
+ movieDetails.append(runtime);
+ }
+ if (event.data.movie.plot) {
+ var plot = $('<p>');
+ plot.addClass('plot').html(event.data.movie.plot);
+ movieDetails.append(plot);
+ }
+ if (event.data.movie.genre) {
+ var genre = $('<p>');
+ genre.addClass('genre').html('<strong>Genre:</strong> ' + event.data.movie.genre);
+ movieDetails.append(genre);
+ }
+ if (event.data.movie.rating) {
+ //Todo
+ }
+ if (event.data.movie.director) {
+ var director = $('<p>');
+ director.addClass('director').html('<strong>Directed By:</strong> ' + event.data.movie.director);
+ movieDetails.append(director);
+ }
+ this.activeCover = movieDetails;
+ $('body').append(movieDetails);
+ $('#overlay').show();
+ this.updatePlayButtonLocation();
+ },
+ displayTVShowDetails: function(event) {
+ },
+ playTrack: function(event) {
+ jQuery.post(JSON_RPC + '?ClearPlaylist', '{"jsonrpc": "2.0", "method": "AudioPlaylist.Clear", "id": 1}', jQuery.proxy(function(data) {
+ //check that clear worked.
+ jQuery.post(JSON_RPC + '?AddAlbumToPlaylist', '{"jsonrpc": "2.0", "method": "AudioPlaylist.Add", "params": { "albumid": ' + event.data.album.albumid + ' }, "id": 1}', jQuery.proxy(function(data) {
+ //play specific song in playlist
+ jQuery.post(JSON_RPC + '?PlaylistItemPlay', '{"jsonrpc": "2.0", "method": "AudioPlaylist.Play", "params": { "songid": ' + event.data.song.songid + ' }, "id": 1}', function() {}, 'json');
+ }, this), 'json');
}, this), 'json');
},
- videoLibraryOpen: function() {
- $('#musicLibrary').removeClass('selected');
- $('#videoLibrary').addClass('selected');
- $('#content').html('');
+ movieLibraryOpen: function() {
+ this.resetPage();
+ $('#movieLibrary').addClass('selected');
+ $('.contentContainer').css('z-index', 1);
+ var libraryContainer = $('#movieLibraryContainer');
+ if (!libraryContainer || libraryContainer.length == 0) {
+ $('#spinner').show();
+ jQuery.post(JSON_RPC + '?GetMovies', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "start": 0, "fields": ["genre", "director", "trailer", "tagline", "plot", "plotoutline", "title", "originaltitle", "lastplayed", "showtitle", "firstaired", "duration", "season", "episode", "runtime", "year", "playcount", "rating"] }, "id": 1}', jQuery.proxy(function(data) {
+ if (data && data.result && data.result.movies) {
+ libraryContainer = $('<div>');
+ libraryContainer.css('z-index', 100)
+ .attr('id', 'movieLibraryContainer')
+ .addClass('contentContainer');
+ $('#content').append(libraryContainer);
+ } else {
+ libraryContainer.html('');
+ }
+ $.each($(data.result.movies), jQuery.proxy(function(i, item) {
+ var floatableMovieCover = this.generateThumb('movie', item.thumbnail, item.title, "");
+ floatableMovieCover.bind('click', { movie: item }, jQuery.proxy(this.displayMovieDetails, this));
+ libraryContainer.append(floatableMovieCover);
+ }, this));
+ $('#spinner').hide();
+ libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
+ libraryContainer.trigger('scroll');
+ //$('#libraryContainer img').lazyload();
+ }, this), 'json');
+ } else {
+ libraryContainer.css('z-index', 100);
+ libraryContainer.trigger('scroll');
+ }
+ },
+ tvshowLibraryOpen: function() {
+ this.resetPage();
+ $('#tvshowLibrary').addClass('selected');
+ $('.contentContainer').css('z-index', 1);
+ var libraryContainer = $('#tvshowLibraryContainer');
+ if (!libraryContainer || libraryContainer.length == 0) {
+ $('#spinner').show();
+ jQuery.post(JSON_RPC + '?GetTVShows', '{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "start": 0, "fields": ["genre", "director", "trailer", "tagline", "plot", "plotoutline", "title", "originaltitle", "lastplayed", "showtitle", "firstaired", "duration", "season", "episode", "runtime", "year", "playcount", "rating"] }, "id": 1}', jQuery.proxy(function(data) {
+ if (data && data.result && data.result.tvshows) {
+ libraryContainer = $('<div>');
+ libraryContainer.css('z-index', 100)
+ .attr('id', 'tvshowLibraryContainer')
+ .addClass('contentContainer');
+ $('#content').append(libraryContainer);
+ } else {
+ libraryContainer.html('');
+ }
+ $.each($(data.result.tvshows), jQuery.proxy(function(i, item) {
+ var floatableTVShowCover = this.generateThumb('tvshow', item.thumbnail, item.title, "");
+ floatableTVShowCover.bind('click', { tvshow: item }, jQuery.proxy(this.displayTVShowDetails, this));
+ libraryContainer.append(floatableTVShowCover);
+ }, this));
+ //$('#libraryContainer img').lazyload();
+ $('#spinner').hide();
+ libraryContainer.bind('scroll', { activeLibrary: libraryContainer }, jQuery.proxy(this.updateScrollEffects, this));
+ libraryContainer.trigger('scroll');
+ }, this), 'json');
+ } else {
+ libraryContainer.css('z-index', 100);
+ libraryContainer.trigger('scroll');
+ }
+ },
+ updateScrollEffects: function(event) {
+ if (event.data.activeLibrary && $(event.data.activeLibrary).scrollTop() > 0) {
+ $('#topScrollFade').fadeIn();
+ } else {
+ $('#topScrollFade').fadeOut();
+ }
}
} \ No newline at end of file
diff --git a/addons/webinterface.default/js/NowPlayingManager.js b/addons/webinterface.default/js/NowPlayingManager.js
index d608bd86f6..29278ece3f 100644
--- a/addons/webinterface.default/js/NowPlayingManager.js
+++ b/addons/webinterface.default/js/NowPlayingManager.js
@@ -35,7 +35,7 @@ NowPlayingManager.prototype = {
$(window).bind('click', jQuery.proxy(this.hidePlaylist, this));
},
updateState: function() {
- jQuery.post(JSON_RPC, '{"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}', jQuery.proxy(function(data) {
+ jQuery.post(JSON_RPC + '?UpdateState', '{"jsonrpc": "2.0", "method": "Player.GetActivePlayers", "id": 1}', jQuery.proxy(function(data) {
if (data && data.result) {
if (data.result.audio) {
this.activePlayer = 'Audio';
@@ -166,8 +166,8 @@ NowPlayingManager.prototype = {
data: '{"jsonrpc": "2.0", "method": "AudioPlaylist.GetItems", "params": { "fields": ["title", "album", "artist", "duration"] }, "id": 1}',
success: jQuery.proxy(function(data) {
if (data && data.result && data.result.items && data.result.total > 0) {
- //Compare new playlist to active playlist, only redraw if a change is noticed.
- if (this.playlistChanged(data.result.items) || (this.activePlaylistItem && (this.activePlaylistItem.seq != data.result.current))) {
+ //Compare new playlist to active playlist, only redraw if a change is noticed
+ if (!this.activePlaylistItem || this.playlistChanged(data.result.items) || (this.activePlaylistItem && (this.activePlaylistItem.seq != data.result.current))) {
var ul = $('<ul>');
var activeItem;
$.each($(data.result.items), jQuery.proxy(function(i, item) {
@@ -179,16 +179,17 @@ NowPlayingManager.prototype = {
li.addClass('activeItem');
}
if (i == (data.result.current + 1)) {
- $('#nextTrack').html(code);
- $('#nextTrack').show();
+ $('#nextTrack').html(code).show();
}
li.bind('click', jQuery.proxy(this.playPlaylistItem, this));
ul.append(li.attr('seq', i).html(code));
}, this));
if (data.result.total > 1) {
+ if (activeItem && data.result.total-1 == activeItem.seq) {
+ $('#nextTrack').html('<div class="trackInfo">Last track in playlist</div>').show();
+ }
$('#nextText').show();
- $('#nowPlayingPlaylist').html('')
- .append(ul);
+ $('#nowPlayingPlaylist').html('').append(ul);
} else {
$('#nextText').hide();
$('#nowPlayingPlaylist').hide();
@@ -226,12 +227,10 @@ NowPlayingManager.prototype = {
});
},
stopAudioPlaylistUpdate: function() {
- this.stopRefreshTime();
this.autoRefreshAudioPlaylist = false;
this.updateActiveItemDurationRunOnce = false;
},
stopVideoPlaylistUpdate: function() {
- this.stopRefreshTime();
this.autoRefreshVideoPlaylist = false;
this.updateActiveItemDurationRunOnce = false;
},
@@ -255,10 +254,10 @@ NowPlayingManager.prototype = {
this.refreshVideoData();
}
}
- if (this.autoRefreshData && !this.activeItemTimer) {
- this.activeItemTimer = 1;
- setTimeout(jQuery.proxy(this.updateActiveItemDurationLoop, this), 1000);
- }
+ }
+ if (this.autoRefreshData && !this.activeItemTimer) {
+ this.activeItemTimer = 1;
+ setTimeout(jQuery.proxy(this.updateActiveItemDurationLoop, this), 1000);
}
}, this), 'json');
},
@@ -409,15 +408,17 @@ NowPlayingManager.prototype = {
li.addClass('activeItem');
}
if (i == (data.result.current + 1)) {
- $('#nextTrack').html(code);
+ $('#nextTrack').html(code).show();
}
li.bind('click', jQuery.proxy(this.playPlaylistItem, this));
ul.append(li.attr('seq', i).html(code));
}, this));
if (data.result.total > 1) {
$('#nextText').show();
- $('#nowPlayingPlaylist').html('')
- .append(ul);
+ if (activeItem && data.result.total == activeItem.seq) {
+ $('#nextTrack').html('<div class="trackInfo">Last track in playlist</div>').show();
+ }
+ $('#nowPlayingPlaylist').html('').append(ul);
} else {
$('#nextText').hide();
$('#nowPlayingPlaylist').hide();
diff --git a/tools/Linux/packaging/debian/rules.hardy b/tools/Linux/packaging/debian/rules.hardy
index 74ca818b2f..fbb7a5c871 100755
--- a/tools/Linux/packaging/debian/rules.hardy
+++ b/tools/Linux/packaging/debian/rules.hardy
@@ -45,7 +45,7 @@ binary: binary-arch binary-indep
binary-indep:
dh binary-indep --until dh_installdirs
- $(MAKE) install-web install-datas install-livedatas prefix=$(CURDIR)/debian/tmp/usr/
+ $(MAKE) install-datas install-livedatas prefix=$(CURDIR)/debian/tmp/usr/
mkdir -p $(CURDIR)/debian/tmp/usr/share/applications $(CURDIR)/debian/tmp/usr/share/pixmaps
cp $(CURDIR)/tools/Linux/xbmc.png $(CURDIR)/debian/tmp/usr/share/pixmaps/
cp $(CURDIR)/tools/Linux/xbmc.desktop $(CURDIR)/debian/tmp/usr/share/applications/
diff --git a/xbmc/ApplicationMessenger.cpp b/xbmc/ApplicationMessenger.cpp
index 0b87b85f28..3020102892 100644
--- a/xbmc/ApplicationMessenger.cpp
+++ b/xbmc/ApplicationMessenger.cpp
@@ -471,7 +471,13 @@ case TMSG_POWERDOWN:
g_playlistPlayer.Play(pMsg->dwParam1);
else
g_playlistPlayer.Play();
+ break;
+ case TMSG_PLAYLISTPLAYER_PLAY_SONG_ID:
+ if (pMsg->dwParam1 != (DWORD) -1)
+ g_playlistPlayer.PlaySongId(pMsg->dwParam1);
+ else
+ g_playlistPlayer.Play();
break;
case TMSG_PLAYLISTPLAYER_NEXT:
@@ -763,6 +769,12 @@ void CApplicationMessenger::PlayListPlayerPlay(int iSong)
SendMessage(tMsg, true);
}
+void CApplicationMessenger::PlayListPlayerPlaySongId(int songId)
+{
+ ThreadMessage tMsg = {TMSG_PLAYLISTPLAYER_PLAY_SONG_ID, songId};
+ SendMessage(tMsg, true);
+}
+
void CApplicationMessenger::PlayListPlayerNext()
{
ThreadMessage tMsg = {TMSG_PLAYLISTPLAYER_NEXT};
diff --git a/xbmc/ApplicationMessenger.h b/xbmc/ApplicationMessenger.h
index 8f10eeb860..cd0ea75e03 100644
--- a/xbmc/ApplicationMessenger.h
+++ b/xbmc/ApplicationMessenger.h
@@ -49,6 +49,7 @@ class CGUIDialog;
#define TMSG_PLAYLISTPLAYER_CLEAR 214
#define TMSG_PLAYLISTPLAYER_SHUFFLE 215
#define TMSG_PLAYLISTPLAYER_GET_ITEMS 216
+#define TMSG_PLAYLISTPLAYER_PLAY_SONG_ID 217
#define TMSG_PICTURE_SHOW 220
#define TMSG_PICTURE_SLIDESHOW 221
@@ -117,6 +118,7 @@ public:
void PlayListPlayerPlay();
void PlayListPlayerPlay(int iSong);
+ void PlayListPlayerPlaySongId(int songId);
void PlayListPlayerNext();
void PlayListPlayerPrevious();
void PlayListPlayerAdd(int playlist, const CFileItem &item);
diff --git a/xbmc/DateTime.cpp b/xbmc/DateTime.cpp
index eb499c50d5..5be49c31ea 100644
--- a/xbmc/DateTime.cpp
+++ b/xbmc/DateTime.cpp
@@ -1208,3 +1208,35 @@ CStdString CDateTime::GetAsLocalizedDateTime(bool longDate/*=false*/, bool withS
{
return GetAsLocalizedDate(longDate)+" "+GetAsLocalizedTime("", withSeconds);
}
+
+CDateTime CDateTime::GetAsUTCDateTime() const
+{
+ TIME_ZONE_INFORMATION tz;
+
+ CDateTime time(m_time);
+ switch(GetTimeZoneInformation(&tz))
+ {
+ case TIME_ZONE_ID_DAYLIGHT:
+ time += CDateTimeSpan(0, 0, tz.Bias + tz.DaylightBias, 0);
+ break;
+ case TIME_ZONE_ID_STANDARD:
+ time += CDateTimeSpan(0, 0, tz.Bias + tz.StandardBias, 0);
+ break;
+ case TIME_ZONE_ID_UNKNOWN:
+ time += CDateTimeSpan(0, 0, tz.Bias, 0);
+ break;
+ }
+
+ return time;
+}
+
+static const char *DAY_NAMES[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+static const char *MONTH_NAMES[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+CStdString CDateTime::GetAsRFC1123DateTime() const
+{
+ CDateTime time(GetAsUTCDateTime());
+ CStdString result;
+ result.Format("%s, %02i %s %04i %02i:%02i:%02i GMT", DAY_NAMES[time.GetDayOfWeek()], time.GetDay(), MONTH_NAMES[time.GetMonth()-1], time.GetYear(), time.GetHour(), time.GetMinute(), time.GetSecond());
+ return result;
+} \ No newline at end of file
diff --git a/xbmc/DateTime.h b/xbmc/DateTime.h
index b1dbc48b9a..5483ace239 100644
--- a/xbmc/DateTime.h
+++ b/xbmc/DateTime.h
@@ -176,11 +176,13 @@ public:
void GetAsTm(tm& time) const;
void GetAsTimeStamp(FILETIME& time) const;
+ CDateTime GetAsUTCDateTime() const;
CStdString GetAsDBDateTime() const;
CStdString GetAsDBDate() const;
CStdString GetAsLocalizedDate(bool longDate=false) const;
CStdString GetAsLocalizedTime(const CStdString &format, bool withSeconds=true) const;
CStdString GetAsLocalizedDateTime(bool longDate=false, bool withSeconds=true) const;
+ CStdString GetAsRFC1123DateTime() const;
void SetValid(bool yesNo);
bool IsValid() const;
diff --git a/xbmc/FileSystem/MusicDatabaseDirectory/DirectoryNodeAlbum.cpp b/xbmc/FileSystem/MusicDatabaseDirectory/DirectoryNodeAlbum.cpp
index 81477d81e2..c7688096e8 100644
--- a/xbmc/FileSystem/MusicDatabaseDirectory/DirectoryNodeAlbum.cpp
+++ b/xbmc/FileSystem/MusicDatabaseDirectory/DirectoryNodeAlbum.cpp
@@ -45,7 +45,7 @@ bool CDirectoryNodeAlbum::GetContent(CFileItemList& items)
CQueryParams params;
CollectQueryParams(params);
- bool bSuccess=musicdatabase.GetAlbumsNav(BuildPath(), items, params.GetGenreId(), params.GetArtistId());
+ bool bSuccess=musicdatabase.GetAlbumsNav(BuildPath(), items, params.GetGenreId(), params.GetArtistId(),-1,-1);
musicdatabase.Close();
diff --git a/xbmc/GUIDialogSmartPlaylistRule.cpp b/xbmc/GUIDialogSmartPlaylistRule.cpp
index 5b7a903765..991cdc544c 100644
--- a/xbmc/GUIDialogSmartPlaylistRule.cpp
+++ b/xbmc/GUIDialogSmartPlaylistRule.cpp
@@ -140,7 +140,7 @@ void CGUIDialogSmartPlaylistRule::OnBrowse()
else if (m_rule.m_field == CSmartPlaylistRule::FIELD_ALBUM)
{
if (m_type.Equals("songs") || m_type.Equals("mixed") || m_type.Equals("albums"))
- database.GetAlbumsNav("musicdb://6/",items,-1,-1);
+ database.GetAlbumsNav("musicdb://6/",items,-1,-1,-1,-1);
if (m_type.Equals("musicvideos") || m_type.Equals("mixed"))
{
CFileItemList items2;
diff --git a/xbmc/MusicDatabase.cpp b/xbmc/MusicDatabase.cpp
index d67be637fc..c7f42948c9 100644
--- a/xbmc/MusicDatabase.cpp
+++ b/xbmc/MusicDatabase.cpp
@@ -2813,8 +2813,15 @@ bool CMusicDatabase::GetAlbumFromSong(const CSong &song, CAlbum &album)
return false;
}
-bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist)
+bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist, int start, int end)
{
+ //Create limit
+ CStdString limit;
+ if (start >= 0 && end >= 0)
+ {
+ limit.Format(" limit %i,%i", start, end);
+ }
+
// where clause
CStdString strWhere;
if (idGenre!=-1)
@@ -2830,7 +2837,7 @@ bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& i
"join exgenresong on song.idSong=exgenresong.idSong "
"where exgenresong.idGenre=%i"
")"
- ") "
+ ") " + limit
, idGenre, idGenre);
}
@@ -2862,15 +2869,15 @@ bool CMusicDatabase::GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& i
"select exartistalbum.idAlbum from exartistalbum " // All albums where extra album artists fit
"where exartistalbum.idArtist=%i"
")"
- ") "
+ ") " + limit
, idArtist, idArtist, idArtist, idArtist);
}
else
{ // no artist given, so exclude any single albums (aka empty tagged albums)
if (strWhere.IsEmpty())
- strWhere += "where albumview.strAlbum <> ''";
+ strWhere += "where albumview.strAlbum <> ''" + limit;
else
- strWhere += "and albumview.strAlbum <> ''";
+ strWhere += "and albumview.strAlbum <> ''" + limit;
}
bool bResult = GetAlbumsByWhere(strBaseDir, strWhere, "", items);
diff --git a/xbmc/MusicDatabase.h b/xbmc/MusicDatabase.h
index 45450ff190..e59bba9341 100644
--- a/xbmc/MusicDatabase.h
+++ b/xbmc/MusicDatabase.h
@@ -158,7 +158,7 @@ public:
bool GetGenresNav(const CStdString& strBaseDir, CFileItemList& items);
bool GetYearsNav(const CStdString& strBaseDir, CFileItemList& items);
bool GetArtistsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, bool albumArtistsOnly);
- bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist);
+ bool GetAlbumsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist, int start, int end);
bool GetAlbumsByYear(const CStdString &strBaseDir, CFileItemList& items, int year);
bool GetSongsNav(const CStdString& strBaseDir, CFileItemList& items, int idGenre, int idArtist,int idAlbum);
bool GetSongsByYear(const CStdString& baseDir, CFileItemList& items, int year);
diff --git a/xbmc/MusicInfoScanner.cpp b/xbmc/MusicInfoScanner.cpp
index e4614d3fb4..475c1a0a03 100644
--- a/xbmc/MusicInfoScanner.cpp
+++ b/xbmc/MusicInfoScanner.cpp
@@ -237,7 +237,7 @@ void CMusicInfoScanner::FetchAlbumInfo(const CStdString& strDirectory)
if (strDirectory.IsEmpty())
{
m_musicDatabase.Open();
- m_musicDatabase.GetAlbumsNav("musicdb://3/",items,-1,-1);
+ m_musicDatabase.GetAlbumsNav("musicdb://3/",items,-1,-1,-1,-1);
m_musicDatabase.Close();
}
else
diff --git a/xbmc/PlayListPlayer.cpp b/xbmc/PlayListPlayer.cpp
index eb6c0c5f03..d81bfae895 100644
--- a/xbmc/PlayListPlayer.cpp
+++ b/xbmc/PlayListPlayer.cpp
@@ -30,6 +30,7 @@
#include "PlayList.h"
#include "utils/log.h"
#include "utils/TimeUtils.h"
+#include "MusicInfoTag.h"
using namespace PLAYLIST;
@@ -203,6 +204,26 @@ void CPlayListPlayer::Play()
Play(0);
}
+void CPlayListPlayer::PlaySongId(int songId)
+{
+ if (m_iCurrentPlayList == PLAYLIST_NONE)
+ return;
+
+ CPlayList& playlist = GetPlaylist(m_iCurrentPlayList);
+ if (playlist.size() <= 0)
+ Play();
+
+ for (int i = 0; i < playlist.size(); i++)
+ {
+ if (playlist[i]->HasMusicInfoTag() && playlist[i]->GetMusicInfoTag()->GetDatabaseId() == songId)
+ {
+ Play(i);
+ return;
+ }
+ }
+ Play();
+}
+
void CPlayListPlayer::Play(int iSong, bool bAutoPlay /* = false */, bool bPlayPrevious /* = false */)
{
if (m_iCurrentPlayList == PLAYLIST_NONE)
diff --git a/xbmc/PlayListPlayer.h b/xbmc/PlayListPlayer.h
index 0b4a5cf354..103cd1e545 100644
--- a/xbmc/PlayListPlayer.h
+++ b/xbmc/PlayListPlayer.h
@@ -58,7 +58,7 @@ public:
\sa PlayNext
*/
void PlayPrevious();
-
+ void PlaySongId(int songId);
void Play();
/*! \brief Start playing a particular entry in the current playlist
diff --git a/xbmc/lib/libjsonrpc/AVPlaylistOperations.cpp b/xbmc/lib/libjsonrpc/AVPlaylistOperations.cpp
index 11dad4ac48..755e14329c 100644
--- a/xbmc/lib/libjsonrpc/AVPlaylistOperations.cpp
+++ b/xbmc/lib/libjsonrpc/AVPlaylistOperations.cpp
@@ -40,7 +40,13 @@ JSON_STATUS CAVPlaylistOperations::Play(const CStdString &method, ITransportLaye
if (parameterObject.isInt())
g_application.getApplicationMessenger().PlayListPlayerPlay(parameterObject.asInt());
else
- g_application.getApplicationMessenger().PlayListPlayerPlay();
+ {
+ int songId = (parameterObject.isMember("songid") && parameterObject["songid"].isInt()) ? parameterObject["songid"].asInt() : 0;
+ if (songId > 0)
+ g_application.getApplicationMessenger().PlayListPlayerPlaySongId(songId);
+ else
+ g_application.getApplicationMessenger().PlayListPlayerPlay();
+ }
NotifyAll();
return ACK;
diff --git a/xbmc/lib/libjsonrpc/AudioLibrary.cpp b/xbmc/lib/libjsonrpc/AudioLibrary.cpp
index 6a6025f74e..dae895074e 100644
--- a/xbmc/lib/libjsonrpc/AudioLibrary.cpp
+++ b/xbmc/lib/libjsonrpc/AudioLibrary.cpp
@@ -69,9 +69,11 @@ JSON_STATUS CAudioLibrary::GetAlbums(const CStdString &method, ITransportLayer *
int artistID = ParameterAsInt(param, -1, "artistid");
int genreID = ParameterAsInt(param, -1, "genreid");
+ int start = ParameterAsInt(param, -1, "start");
+ int end = ParameterAsInt(param, -1, "end");
CFileItemList items;
- if (musicdatabase.GetAlbumsNav("", items, genreID, artistID))
+ if (musicdatabase.GetAlbumsNav("", items, genreID, artistID, start, end))
HandleFileItemList("albumid", false, "albums", items, param, result);
musicdatabase.Close();
diff --git a/xbmc/lib/libjsonrpc/JSONRPC.cpp b/xbmc/lib/libjsonrpc/JSONRPC.cpp
index 5768660cf8..a8c8baf6d4 100644
--- a/xbmc/lib/libjsonrpc/JSONRPC.cpp
+++ b/xbmc/lib/libjsonrpc/JSONRPC.cpp
@@ -302,7 +302,6 @@ JSON_STATUS CJSONRPC::Announce(const CStdString &method, ITransportLayer *transp
CStdString CJSONRPC::MethodCall(const CStdString &inputString, ITransportLayer *transport, IClient *client)
{
- CLog::Log(LOGDEBUG, "JSONRPC: %s", inputString.c_str());
Value inputroot, outputroot, result;
JSON_STATUS errorCode = OK;
diff --git a/xbmc/utils/WebServer.cpp b/xbmc/utils/WebServer.cpp
index 1ef7f740d1..ebdb38890b 100644
--- a/xbmc/utils/WebServer.cpp
+++ b/xbmc/utils/WebServer.cpp
@@ -28,6 +28,7 @@
#include "../Util.h"
#include "log.h"
#include "SingleLock.h"
+#include "DateTime.h"
#include "addons/AddonManager.h"
#ifdef _WIN32
@@ -111,8 +112,6 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
unsigned int *upload_data_size, void **con_cls)
#endif
{
- CLog::Log(LOGNOTICE, "WebServer: %s | %s", method, url);
-
CWebServer *server = (CWebServer *)cls;
CStdString strURL = url;
CStdString originalURL = url;
@@ -210,10 +209,6 @@ int CWebServer::JSONRPC(CWebServer *server, void **con_cls, struct MHD_Connectio
{
CStdString *jsoncall = (CStdString *)(*con_cls);
- if (jsoncall->size() > 2000)
- CLog::Log(LOGINFO, "JSONRPC: Recieved a jsonrpc call wich is longer than 2000 characters, skipping logging it");
- else
- CLog::Log(LOGINFO, "JSONRPC: Recieved a jsonrpc call - %s", jsoncall->c_str());
CHTTPClient client;
CStdString jsonresponse = CJSONRPC::MethodCall(*jsoncall, server, &client);
@@ -261,13 +256,14 @@ int CWebServer::CreateFileDownloadResponse(struct MHD_Connection *connection, co
{
int ret = MHD_NO;
CFile *file = new CFile();
- if (file->Open(strURL))
+
+ if (file->Open(strURL, READ_NO_CACHE))
{
struct MHD_Response *response;
response = MHD_create_response_from_callback ( file->GetLength(),
2048,
&CWebServer::ContentReaderCallback, file,
- &CWebServer::ContentReaderFreeCallback);
+ &CWebServer::ContentReaderFreeCallback);
CStdString ext = CUtil::GetExtension(strURL);
ext = ext.ToLower();
@@ -275,7 +271,12 @@ int CWebServer::CreateFileDownloadResponse(struct MHD_Connection *connection, co
if (mime)
MHD_add_response_header(response, "Content-Type", mime);
+ CDateTime expiryTime = CDateTime::GetCurrentDateTime();
+ expiryTime += CDateTimeSpan(1, 0, 0, 0);
+ MHD_add_response_header(response, "Expires", expiryTime.GetAsRFC1123DateTime());
+
ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+
MHD_destroy_response(response);
}
else
@@ -284,7 +285,6 @@ int CWebServer::CreateFileDownloadResponse(struct MHD_Connection *connection, co
CLog::Log(LOGERROR, "WebServer: Failed to open %s", strURL.c_str());
return CreateErrorResponse(connection, MHD_HTTP_NOT_FOUND, GET); /* GET Assumed Temporarily */
}
-
return ret;
}
@@ -353,10 +353,12 @@ bool CWebServer::Start(const char *ip, int port)
// WARNING: when using MHD_USE_THREAD_PER_CONNECTION, set MHD_OPTION_CONNECTION_TIMEOUT to something higher than 1
// otherwise on libmicrohttpd 0.4.4-1 it spins a busy loop
- // To stream perfectly we should probably have MHD_USE_THREAD_PER_CONNECTION instead of MHD_USE_SELECT_INTERNALLY as it provides multiple clients concurrently
- m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY | MHD_USE_IPv6, port, NULL, NULL, &CWebServer::AnswerToConnection, this, MHD_OPTION_END);
+ unsigned int timeout = 60 * 60 * 24;
+ // MHD_USE_THREAD_PER_CONNECTION = one thread per connection
+ // MHD_USE_SELECT_INTERNALLY = use main thread for each connection, can only handle one request at a time [unless you set the thread pool size]
+ m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY | MHD_USE_IPv6, port, NULL, NULL, &CWebServer::AnswerToConnection, this, MHD_OPTION_THREAD_POOL_SIZE, 8, MHD_OPTION_CONNECTION_LIMIT, 512, MHD_OPTION_CONNECTION_TIMEOUT, timeout, MHD_OPTION_END);
if (!m_daemon) //try IPv4
- m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, this, &CWebServer::AnswerToConnection, this, MHD_OPTION_END);
+ m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, port, NULL, this, &CWebServer::AnswerToConnection, this, MHD_OPTION_THREAD_POOL_SIZE, 8, MHD_OPTION_CONNECTION_LIMIT, 512, MHD_OPTION_CONNECTION_TIMEOUT, timeout, MHD_OPTION_END);
m_running = m_daemon != NULL;
if (m_running)
CLog::Log(LOGNOTICE, "WebServer: Started the webserver");
@@ -373,7 +375,8 @@ bool CWebServer::Stop()
MHD_stop_daemon(m_daemon);
m_running = false;
CLog::Log(LOGNOTICE, "WebServer: Stopped the webserver");
- }
+ } else
+ CLog::Log(LOGNOTICE, "WebServer: Stopped failed because its not running");
return !m_running;
}