New Webserver and WebApp (#942)
* Replace the WCF webserver with an ASP.NET Core webserver (VocaluxeWeb) - New project VocaluxeWeb: ASP.NET Core 2.3 (Kestrel) on .NET Framework 4.8.1, HTTP or HTTPS with a self-signed certificate, REST API (/api/v1) with Swagger, live events (Server-Sent Events) - Access to the game only through IVocaluxeRemote; requests run on the main thread once per frame - Sessions with roles (guest, player, admin) and configurable permissions, PINs hashed with PBKDF2 - Queue as a playlist with requesters and singers, fair order (one song per person and round) - Admin: settings, server status, logged-in devices, activate/deactivate and delete profiles - Profile pictures: own photo or one of the Vocaluxe avatars - Game: WebApp queue screen (song options, playlist group) to start the next song with the chosen singers, return to it after singing, warning when the webserver is off, remote keyboard - Old WCF server, WebserverInitalConfig and URL reservations removed; libraries moved to libs/managed - Unit tests for PIN hashing, settings and permissions, queue order and device names - AppVeyor: Visual Studio 2022 image and Node.js 24 (the build compiles the WebApp) - Documentation in VocaluxeWeb/README.md * New WebApp (Vue 3, TypeScript, Vite) replacing the old jQuery Mobile website - Login with profile and PIN, create profiles - Songs with search, filters, sorting and 30 second previews - Queue: add songs with game mode, audio and singers, edit, reorder, start in the game - Playlists: create, edit, add to the queue - Now playing with live updates, remote control and keyboard - Players: own profile with picture (photo or Vocaluxe avatar), roles for admins - Admin settings: permissions, server status, devices, profiles - Help page, responsive layout for phones, tablets and desktops, light and dark mode - Texts in WebApp/src/locales/en.json, translated with Transifex - Old website and PhoneGap config removed --------- Co-authored-by: Florian Ostertag <flokuep@users.noreply.github.com>
No files matched your search
@@ -43,11 +43,13 @@ tx.exe
|
||||
/Output/Vocaluxe_x64.exe*
|
||||
/Output/Vocaluxe.vshost.exe*
|
||||
/Output/VocaluxeLib.dll
|
||||
/Output/VocaluxeServerConfig.exe
|
||||
/Output/VocaluxeServerConfig.exe.config
|
||||
/Output/Photos
|
||||
/Output/Screenshots
|
||||
/Output/Website
|
||||
/Output/WebServer.pfx
|
||||
/Output/WebServer.json
|
||||
/Output/WebCache
|
||||
/VocaluxeWeb/bin
|
||||
/Output/Songs
|
||||
/Output/Playlists/*.xml
|
||||
/Output/Profiles/*.xml
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
* Make sure [Visual Studio 2012/2013(?)](http://www.visualstudio.com/downloads/download-visual-studio-vs#d-express-windows-desktop) is installed
|
||||
|
||||
* Make sure [Node.js (LTS)](https://nodejs.org) is installed. It is needed to build the WebApp (folder `WebApp`), which is built automatically together with the project `VocaluxeWeb`. Restart Visual Studio after installing it.
|
||||
|
||||
* Clone the repository and open it
|
||||
|
||||
**Method A: Use Visual Studio (2013+)'s git client:**
|
||||
|
||||
@@ -166,6 +166,21 @@
|
||||
<string name="TR_SCREENJUKEBOX_VIDEO">Video</string>
|
||||
<string name="TR_SCREENJUKEBOX_NUMSONGS">%d songs</string>
|
||||
<string name="TR_SCREENJUKEBOX_NOSONGS">No songs found</string>
|
||||
<string name="TR_SCREENWEBQUEUE_TITLE">WebApp Queue</string>
|
||||
<string name="TR_SCREENWEBQUEUE_NEXT">Up next</string>
|
||||
<string name="TR_SCREENWEBQUEUE_HINT">Add songs with the WebApp</string>
|
||||
<string name="TR_SCREENWEBQUEUE_SERVEROFF">The webserver is off - switch it on under Options - Server to use the WebApp</string>
|
||||
<string name="TR_SCREENWEBQUEUE_EMPTY">The queue is empty.</string>
|
||||
<string name="TR_SCREENWEBQUEUE_EMPTY2">Add songs with the WebApp (QR code: Server address).</string>
|
||||
<string name="TR_SCREENSONG_BUTTON_WEBQUEUE">WebApp Queue</string>
|
||||
<string name="TR_SCREENWEBQUEUE_ADDEDBY">added by %s</string>
|
||||
<string name="TR_SCREENWEBQUEUE_SINGERS">Singers: %s</string>
|
||||
<string name="TR_SCREENWEBQUEUE_NOSINGERS">Singers are chosen before singing</string>
|
||||
<string name="TR_SCREENWEBQUEUE_MORE">+ %d more</string>
|
||||
<string name="TR_SCREENWEBQUEUE_MODE">Game mode</string>
|
||||
<string name="TR_SCREENWEBQUEUE_AUDIO">Audio</string>
|
||||
<string name="TR_SCREENWEBQUEUE_PLAYERS">Change players</string>
|
||||
<string name="TR_SCREENWEBQUEUE_SING">Sing</string>
|
||||
<string name="TR_JUKEBOX_ORDER_RANDOM">Random</string>
|
||||
<string name="TR_JUKEBOX_ORDER_SORTED">In order</string>
|
||||
<string name="TR_JUKEBOX_SECTION_FULL">Full song</string>
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
ScreenSong
|
||||
|
||||
++++++++++
|
||||
Version 17:
|
||||
|
||||
Add:
|
||||
<ButtonOptionsWebQueue> (opens the WebApp queue, below the playlist selection in the playlist group of the song options)
|
||||
|
||||
++++++++++
|
||||
Version 16:
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ScreenWebQueue
|
||||
|
||||
++++++++++
|
||||
Version 1:
|
||||
|
||||
New screen: queue of the WebApp (next song with requester, game mode, audio mode and singers, list of the following songs; sing the next song, change players, server address)
|
||||
@@ -2,7 +2,7 @@
|
||||
<Screen xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Informations>
|
||||
<ScreenName>ScreenSong</ScreenName>
|
||||
<ScreenVersion>16</ScreenVersion>
|
||||
<ScreenVersion>17</ScreenVersion>
|
||||
</Informations>
|
||||
<Backgrounds>
|
||||
<Background Name="Background1">
|
||||
@@ -104,13 +104,13 @@
|
||||
</Rect>
|
||||
</Static>
|
||||
<Static Name="StaticOptionsGroupPlaylist">
|
||||
<Skin>OptionsGroupSmall</Skin>
|
||||
<Skin>OptionsGroupLarge</Skin>
|
||||
<Color Name="ButtonMainColor" />
|
||||
<Rect>
|
||||
<X>60</X>
|
||||
<Y>630</Y>
|
||||
<W>540</W>
|
||||
<H>110</H>
|
||||
<H>160</H>
|
||||
<Z>-2.105</Z>
|
||||
</Rect>
|
||||
</Static>
|
||||
@@ -262,7 +262,7 @@
|
||||
<Color Name="White" />
|
||||
<Rect>
|
||||
<X>76</X>
|
||||
<Y>767</Y>
|
||||
<Y>817</Y>
|
||||
<W>36</W>
|
||||
<H>36</H>
|
||||
<Z>-2.13</Z>
|
||||
@@ -273,7 +273,7 @@
|
||||
<Color Name="White" />
|
||||
<Rect>
|
||||
<X>351</X>
|
||||
<Y>767</Y>
|
||||
<Y>817</Y>
|
||||
<W>36</W>
|
||||
<H>36</H>
|
||||
<Z>-2.13</Z>
|
||||
@@ -990,7 +990,7 @@
|
||||
<SkinSelected>SongSelectButton</SkinSelected>
|
||||
<Rect>
|
||||
<X>335</X>
|
||||
<Y>755</Y>
|
||||
<Y>805</Y>
|
||||
<W>265</W>
|
||||
<H>60</H>
|
||||
<Z>-2.11</Z>
|
||||
@@ -1290,6 +1290,33 @@
|
||||
<Text>TR_SCREENSONG_BUTTON_RANDOMMEDLEY</Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonOptionsWebQueue">
|
||||
<Skin>SongSelectButton</Skin>
|
||||
<SkinSelected>SongSelectButton</SkinSelected>
|
||||
<Rect>
|
||||
<X>76</X>
|
||||
<Y>732</Y>
|
||||
<W>508</W>
|
||||
<H>44</H>
|
||||
<Z>-2.11</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>254</X>
|
||||
<Y>4</Y>
|
||||
<Z>0</Z>
|
||||
<H>36</H>
|
||||
<MaxW>490</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENSONG_BUTTON_WEBQUEUE</Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonOptionsStartMedley">
|
||||
<Skin>Button</Skin>
|
||||
<SkinSelected>Button</SkinSelected>
|
||||
@@ -1322,7 +1349,7 @@
|
||||
<SkinSelected>SongSelectButton</SkinSelected>
|
||||
<Rect>
|
||||
<X>60</X>
|
||||
<Y>755</Y>
|
||||
<Y>805</Y>
|
||||
<W>265</W>
|
||||
<H>60</H>
|
||||
<Z>-2.11</Z>
|
||||
|
||||
@@ -0,0 +1,684 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Screen xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<Informations>
|
||||
<ScreenName>ScreenWebQueue</ScreenName>
|
||||
<ScreenVersion>1</ScreenVersion>
|
||||
</Informations>
|
||||
<Backgrounds>
|
||||
<Background Name="Background1">
|
||||
<Type>Video</Type>
|
||||
<SlideShowTextures />
|
||||
<Video>BG_Video</Video>
|
||||
<Skin>BG_Options</Skin>
|
||||
<Color Name="BackgroundColor" />
|
||||
</Background>
|
||||
</Backgrounds>
|
||||
<Statics>
|
||||
<Static Name="StaticMenuBar">
|
||||
<Skin />
|
||||
<Color Name="BackgroundColorAlpha" />
|
||||
<Rect>
|
||||
<X>0</X>
|
||||
<Y>60</Y>
|
||||
<W>1920</W>
|
||||
<H>67.5</H>
|
||||
<Z>1</Z>
|
||||
</Rect>
|
||||
</Static>
|
||||
<Static Name="StaticWarning">
|
||||
<Skin>Warning</Skin>
|
||||
<Color Name="StaticWarningColor" />
|
||||
<Rect>
|
||||
<X>390</X>
|
||||
<Y>142.5</Y>
|
||||
<W>1140</W>
|
||||
<H>75</H>
|
||||
<Z>-1</Z>
|
||||
</Rect>
|
||||
</Static>
|
||||
<Static Name="StaticNextPanel">
|
||||
<Skin />
|
||||
<Color Name="BackgroundColorAlpha" />
|
||||
<Rect>
|
||||
<X>82.5</X>
|
||||
<Y>240</Y>
|
||||
<W>600</W>
|
||||
<H>400</H>
|
||||
<Z>1</Z>
|
||||
</Rect>
|
||||
</Static>
|
||||
<Static Name="StaticNextCover">
|
||||
<Skin>CoverTile</Skin>
|
||||
<Color Name="StaticColor" />
|
||||
<Rect>
|
||||
<X>282.5</X>
|
||||
<Y>300</Y>
|
||||
<W>200</W>
|
||||
<H>200</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
</Static>
|
||||
</Statics>
|
||||
<Texts>
|
||||
<Text Name="TextTitle">
|
||||
<X>960</X>
|
||||
<Y>75</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>1500</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_TITLE</Text>
|
||||
</Text>
|
||||
<Text Name="TextInfo">
|
||||
<X>960</X>
|
||||
<Y>161</Y>
|
||||
<Z>0</Z>
|
||||
<H>37.5</H>
|
||||
<MaxW>1500</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_HINT</Text>
|
||||
</Text>
|
||||
<Text Name="TextWarning">
|
||||
<X>960</X>
|
||||
<Y>161</Y>
|
||||
<Z>-1.1</Z>
|
||||
<H>37.5</H>
|
||||
<MaxW>960</MaxW>
|
||||
<Color Name="TextWarningColor" />
|
||||
<SelColor Name="TextWarningColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_SERVEROFF</Text>
|
||||
</Text>
|
||||
<Text Name="TextNextLabel">
|
||||
<X>382.5</X>
|
||||
<Y>250</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_NEXT</Text>
|
||||
</Text>
|
||||
<Text Name="TextNextSong">
|
||||
<X>382.5</X>
|
||||
<Y>512</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
<Text Name="TextNextDetails">
|
||||
<X>382.5</X>
|
||||
<Y>560</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Normal</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
<Text Name="TextNextPlayers">
|
||||
<X>382.5</X>
|
||||
<Y>598</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Normal</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
<Text Name="TextMode">
|
||||
<X>97.5</X>
|
||||
<Y>660</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_MODE</Text>
|
||||
</Text>
|
||||
<Text Name="TextAudio">
|
||||
<X>97.5</X>
|
||||
<Y>772</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>570</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_AUDIO</Text>
|
||||
</Text>
|
||||
<Text Name="TextEmpty">
|
||||
<X>1293.75</X>
|
||||
<Y>450</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>1000</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_EMPTY</Text>
|
||||
</Text>
|
||||
<Text Name="TextEmpty2">
|
||||
<X>1293.75</X>
|
||||
<Y>502</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1000</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Normal</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_EMPTY2</Text>
|
||||
</Text>
|
||||
<Text Name="TextMore">
|
||||
<X>1293.75</X>
|
||||
<Y>785</Y>
|
||||
<Z>0</Z>
|
||||
<H>30</H>
|
||||
<MaxW>1000</MaxW>
|
||||
<Color Name="TextColor" />
|
||||
<SelColor Name="TextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Normal</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Texts>
|
||||
<Buttons>
|
||||
<Button Name="ButtonEntry1">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>240.0</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry2">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>307.5</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry3">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>375.0</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry4">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>442.5</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry5">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>510.0</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry6">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>577.5</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry7">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>645.0</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonEntry8">
|
||||
<Skin>QueueRow</Skin>
|
||||
<SkinSelected>QueueRow</SkinSelected>
|
||||
<Rect>
|
||||
<X>750</X>
|
||||
<Y>712.5</Y>
|
||||
<W>1087.5</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>22.5</X>
|
||||
<Y>13.5</Y>
|
||||
<Z>0</Z>
|
||||
<H>33</H>
|
||||
<MaxW>1040</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Left</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text></Text>
|
||||
</Text>
|
||||
</Button>
|
||||
<Button Name="ButtonBack">
|
||||
<Skin>Button</Skin>
|
||||
<SkinSelected>Button</SkinSelected>
|
||||
<Rect>
|
||||
<X>82.5</X>
|
||||
<Y>915</Y>
|
||||
<W>262.5</W>
|
||||
<H>75</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>131.25</X>
|
||||
<Y>17.2</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>250.5</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_BUTTON_BACK</Text>
|
||||
</Text>
|
||||
<Reflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</Reflection>
|
||||
<SelReflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</SelReflection>
|
||||
</Button>
|
||||
<Button Name="ButtonServer">
|
||||
<Skin>Button</Skin>
|
||||
<SkinSelected>Button</SkinSelected>
|
||||
<Rect>
|
||||
<X>1012.5</X>
|
||||
<Y>915</Y>
|
||||
<W>262.5</W>
|
||||
<H>75</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>131.25</X>
|
||||
<Y>17.2</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>250.5</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENOSERVER_BUTTON_SERVER</Text>
|
||||
</Text>
|
||||
<Reflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</Reflection>
|
||||
<SelReflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</SelReflection>
|
||||
</Button>
|
||||
<Button Name="ButtonPlayers">
|
||||
<Skin>Button</Skin>
|
||||
<SkinSelected>Button</SkinSelected>
|
||||
<Rect>
|
||||
<X>1297.5</X>
|
||||
<Y>915</Y>
|
||||
<W>262.5</W>
|
||||
<H>75</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>131.25</X>
|
||||
<Y>17.2</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>250.5</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_PLAYERS</Text>
|
||||
</Text>
|
||||
<Reflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</Reflection>
|
||||
<SelReflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</SelReflection>
|
||||
</Button>
|
||||
<Button Name="ButtonStart">
|
||||
<Skin>Button</Skin>
|
||||
<SkinSelected>Button</SkinSelected>
|
||||
<Rect>
|
||||
<X>1582.5</X>
|
||||
<Y>915</Y>
|
||||
<W>262.5</W>
|
||||
<H>75</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<Color Name="ButtonColor" />
|
||||
<SelColor Name="ButtonSelColor" />
|
||||
<Text Name="Text">
|
||||
<X>131.25</X>
|
||||
<Y>17.2</Y>
|
||||
<Z>0</Z>
|
||||
<H>40.5</H>
|
||||
<MaxW>250.5</MaxW>
|
||||
<Color Name="ButtonTextColor" />
|
||||
<SelColor Name="ButtonTextSelColor" />
|
||||
<Align>Center</Align>
|
||||
<ResizeAlign>Center</ResizeAlign>
|
||||
<Style>Bold</Style>
|
||||
<Font>Outline</Font>
|
||||
<Text>TR_SCREENWEBQUEUE_SING</Text>
|
||||
</Text>
|
||||
<Reflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</Reflection>
|
||||
<SelReflection>
|
||||
<Height>39</Height>
|
||||
<Space>15</Space>
|
||||
</SelReflection>
|
||||
</Button>
|
||||
</Buttons>
|
||||
<SongMenus />
|
||||
<Lyrics />
|
||||
<SelectSlides>
|
||||
<SelectSlide Name="SelectSlideMode">
|
||||
<Skin />
|
||||
<SkinArrowLeft>SelectSlideArrowLeft</SkinArrowLeft>
|
||||
<SkinArrowRight>SelectSlideArrowRight</SkinArrowRight>
|
||||
<SkinSelected>SelectSlide</SkinSelected>
|
||||
<SkinArrowLeftSelected>SelectSlideArrowLeft</SkinArrowLeftSelected>
|
||||
<SkinArrowRightSelected>SelectSlideArrowRight</SkinArrowRightSelected>
|
||||
<Rect>
|
||||
<X>82.5</X>
|
||||
<Y>700</Y>
|
||||
<W>600</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<RectArrowLeft>
|
||||
<X>88.5</X>
|
||||
<Y>703.0</Y>
|
||||
<W>54</W>
|
||||
<H>54</H>
|
||||
<Z>0</Z>
|
||||
</RectArrowLeft>
|
||||
<RectArrowRight>
|
||||
<X>622.5</X>
|
||||
<Y>703.0</Y>
|
||||
<W>54</W>
|
||||
<H>54</H>
|
||||
<Z>0</Z>
|
||||
</RectArrowRight>
|
||||
<Color Name="SelectSlideColor" />
|
||||
<SelColor Name="SelectSlideSelColor" />
|
||||
<ArrowColor Name="ArrowColor" />
|
||||
<ArrowSelColor Name="ArrowSelColor" />
|
||||
<TextColor Name="TextColorAlpha" />
|
||||
<TextSelColor Name="TextSelColor" />
|
||||
<TextH>36</TextH>
|
||||
<TextRelativeX>66</TextRelativeX>
|
||||
<TextRelativeY>0</TextRelativeY>
|
||||
<TextMaxW>380</TextMaxW>
|
||||
<TextFont>Outline</TextFont>
|
||||
<TextStyle>Bold</TextStyle>
|
||||
<NumVisible>1</NumVisible>
|
||||
</SelectSlide>
|
||||
<SelectSlide Name="SelectSlideAudio">
|
||||
<Skin />
|
||||
<SkinArrowLeft>SelectSlideArrowLeft</SkinArrowLeft>
|
||||
<SkinArrowRight>SelectSlideArrowRight</SkinArrowRight>
|
||||
<SkinSelected>SelectSlide</SkinSelected>
|
||||
<SkinArrowLeftSelected>SelectSlideArrowLeft</SkinArrowLeftSelected>
|
||||
<SkinArrowRightSelected>SelectSlideArrowRight</SkinArrowRightSelected>
|
||||
<Rect>
|
||||
<X>82.5</X>
|
||||
<Y>812</Y>
|
||||
<W>600</W>
|
||||
<H>60</H>
|
||||
<Z>0</Z>
|
||||
</Rect>
|
||||
<RectArrowLeft>
|
||||
<X>88.5</X>
|
||||
<Y>815.0</Y>
|
||||
<W>54</W>
|
||||
<H>54</H>
|
||||
<Z>0</Z>
|
||||
</RectArrowLeft>
|
||||
<RectArrowRight>
|
||||
<X>622.5</X>
|
||||
<Y>815.0</Y>
|
||||
<W>54</W>
|
||||
<H>54</H>
|
||||
<Z>0</Z>
|
||||
</RectArrowRight>
|
||||
<Color Name="SelectSlideColor" />
|
||||
<SelColor Name="SelectSlideSelColor" />
|
||||
<ArrowColor Name="ArrowColor" />
|
||||
<ArrowSelColor Name="ArrowSelColor" />
|
||||
<TextColor Name="TextColorAlpha" />
|
||||
<TextSelColor Name="TextSelColor" />
|
||||
<TextH>36</TextH>
|
||||
<TextRelativeX>66</TextRelativeX>
|
||||
<TextRelativeY>0</TextRelativeY>
|
||||
<TextMaxW>380</TextMaxW>
|
||||
<TextFont>Outline</TextFont>
|
||||
<TextStyle>Bold</TextStyle>
|
||||
<NumVisible>1</NumVisible>
|
||||
</SelectSlide>
|
||||
</SelectSlides>
|
||||
<SingNotes />
|
||||
<NameSelections />
|
||||
<Equalizers />
|
||||
<Playlists />
|
||||
<ParticleEffects />
|
||||
<ScreenSettings />
|
||||
</Screen>
|
||||
@@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- config.xml reference: https://build.phonegap.com/docs/config-xml -->
|
||||
<widget xmlns = "http://www.w3.org/ns/widgets"
|
||||
xmlns:gap = "http://phonegap.com/ns/1.0"
|
||||
id = "net.sourceforge.vocaluxe"
|
||||
version = "0.1.0">
|
||||
|
||||
<name>Vocaluxe</name>
|
||||
|
||||
<description>
|
||||
Interact with Vocaluxe via your mobile device.
|
||||
</description>
|
||||
|
||||
<author href="http://vocaluxe.sourceforge.net">
|
||||
Vocaluxe Team
|
||||
</author>
|
||||
|
||||
<!--
|
||||
Enable individual API permissions here.
|
||||
-->
|
||||
<feature name="http://api.phonegap.com/1.0/device" />
|
||||
<feature name="http://api.phonegap.com/1.0/camera" />
|
||||
<feature name="http://api.phonegap.com/1.0/file" />
|
||||
|
||||
<!-- Customize your app and platform with the preference element. -->
|
||||
<preference name="phonegap-version" value="2.9.0" />
|
||||
|
||||
<!-- Plugins can also be added here. -->
|
||||
<gap:plugin name="com.phonegap.plugins.barcodescanner" />
|
||||
|
||||
<!-- Define app icon for each platform. -->
|
||||
<icon src="icon.png" />
|
||||
|
||||
<access origin="*" />
|
||||
</widget>
|
||||
@@ -42,6 +42,8 @@ Building Vocaluxe is easy:
|
||||
Just follow the guide on our wiki to clone the repository and create your own Vocaluxe build:
|
||||
[Build Vocaluxe (Windows)](https://github.com/Vocaluxe/Vocaluxe/wiki/HowTo:-Build-Vocaluxe-(Windows))
|
||||
|
||||
The WebApp and the webserver (build with Node.js, development, REST API, translations) are described in [VocaluxeWeb/README.md](VocaluxeWeb/README.md).
|
||||
|
||||
### Submit your change
|
||||
Upload your changes to your fork and open a new pull request.
|
||||
|
||||
|
||||
@@ -85,6 +85,10 @@
|
||||
<Compile Include="VocaluxeLib\Utils\Combinatorics\CCombinationsTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="VocaluxeLib\XML\CXmlSerializerTest.cs" />
|
||||
<Compile Include="VocaluxeWeb\CPinHasherTest.cs" />
|
||||
<Compile Include="VocaluxeWeb\CQueueServiceTest.cs" />
|
||||
<Compile Include="VocaluxeWeb\CUserAgentTest.cs" />
|
||||
<Compile Include="VocaluxeWeb\CWebSettingsTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||
@@ -103,6 +107,10 @@
|
||||
<Project>{2a1e0f2d-5392-4bb7-b0a1-a9dfa13e79ff}</Project>
|
||||
<Name>Vocaluxe</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\VocaluxeWeb\VocaluxeWeb.csproj">
|
||||
<Project>{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}</Project>
|
||||
<Name>VocaluxeWeb</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="VocaluxeLib\XML\TestFiles\Dictionary`2.xml" />
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using NUnit.Framework;
|
||||
using VocaluxeWeb.Services;
|
||||
|
||||
namespace Tests.VocaluxeWeb
|
||||
{
|
||||
[TestFixture]
|
||||
public class CPinHasherTest
|
||||
{
|
||||
[Test]
|
||||
public void TestHashAndVerify()
|
||||
{
|
||||
CPinHasher.Hash("1234", out var hash, out var salt);
|
||||
Assert.That(CPinHasher.Verify("1234", hash, salt), Is.True);
|
||||
Assert.That(CPinHasher.Verify("4321", hash, salt), Is.False);
|
||||
Assert.That(CPinHasher.Verify("", hash, salt), Is.False);
|
||||
Assert.That(CPinHasher.NeedsUpgrade(salt), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSaltIsRandom()
|
||||
{
|
||||
CPinHasher.Hash("1234", out var hash1, out var salt1);
|
||||
CPinHasher.Hash("1234", out var hash2, out var salt2);
|
||||
Assert.That(salt1, Is.Not.EqualTo(salt2));
|
||||
Assert.That(hash1, Is.Not.EqualTo(hash2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMissingValues()
|
||||
{
|
||||
CPinHasher.Hash("1234", out var hash, out var salt);
|
||||
Assert.That(CPinHasher.Verify(null, hash, salt), Is.False);
|
||||
Assert.That(CPinHasher.Verify("1234", null, salt), Is.False);
|
||||
Assert.That(CPinHasher.Verify("1234", hash, null), Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLegacyPin()
|
||||
{
|
||||
var salt = new byte[32];
|
||||
new Random(1).NextBytes(salt);
|
||||
var hash = _LegacyHash("0815", salt);
|
||||
|
||||
Assert.That(CPinHasher.NeedsUpgrade(salt), Is.True);
|
||||
Assert.That(CPinHasher.Verify("0815", hash, salt), Is.True);
|
||||
Assert.That(CPinHasher.Verify("0816", hash, salt), Is.False);
|
||||
}
|
||||
|
||||
private static byte[] _LegacyHash(string pin, byte[] salt)
|
||||
{
|
||||
var password = Encoding.UTF8.GetBytes(pin);
|
||||
var data = new byte[password.Length + salt.Length];
|
||||
password.CopyTo(data, 0);
|
||||
salt.CopyTo(data, password.Length);
|
||||
using (var sha = SHA256.Create())
|
||||
{
|
||||
return sha.ComputeHash(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using VocaluxeWeb;
|
||||
using VocaluxeWeb.Contracts;
|
||||
using VocaluxeWeb.Dispatching;
|
||||
using VocaluxeWeb.Remote;
|
||||
using VocaluxeWeb.Services;
|
||||
|
||||
namespace Tests.VocaluxeWeb
|
||||
{
|
||||
[TestFixture]
|
||||
public class CQueueServiceTest
|
||||
{
|
||||
private sealed class CFakeRemote : IVocaluxeRemote
|
||||
{
|
||||
public readonly List<RemotePlaylist> Playlists = new List<RemotePlaylist>();
|
||||
|
||||
public string Version => "test";
|
||||
public bool IsReady => true;
|
||||
public int SongLibraryVersion => 1;
|
||||
|
||||
public RemoteState GetState()
|
||||
{
|
||||
return new RemoteState { Screen = "Main" };
|
||||
}
|
||||
|
||||
public IList<RemoteProfile> GetProfiles()
|
||||
{
|
||||
return new List<RemoteProfile>();
|
||||
}
|
||||
|
||||
public Guid CreateProfile(ProfileChange change)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void UpdateProfile(Guid profileId, ProfileChange change) { }
|
||||
|
||||
public void DeleteProfile(Guid profileId) { }
|
||||
|
||||
public IList<RemoteAvatar> GetAvatars()
|
||||
{
|
||||
return new List<RemoteAvatar>();
|
||||
}
|
||||
|
||||
public IList<RemoteSong> GetSongs()
|
||||
{
|
||||
return Enumerable.Range(0, 20)
|
||||
.Select(i => new RemoteSong
|
||||
{
|
||||
Id = i,
|
||||
Title = "Song " + i,
|
||||
Artist = "Artist",
|
||||
Languages = new string[0],
|
||||
Genres = new string[0],
|
||||
Editions = new string[0],
|
||||
GameModes = new List<int>(),
|
||||
AudioModes = new List<int>()
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public IList<RemotePlaylist> GetPlaylists()
|
||||
{
|
||||
return Playlists.Select(p => new RemotePlaylist { Id = p.Id, Name = p.Name, Entries = p.Entries.ToList() }).ToList();
|
||||
}
|
||||
|
||||
public int CreatePlaylist(string name)
|
||||
{
|
||||
var playlist = new RemotePlaylist { Id = Playlists.Count + 1, Name = name, Entries = new List<RemotePlaylistEntry>() };
|
||||
Playlists.Add(playlist);
|
||||
return playlist.Id;
|
||||
}
|
||||
|
||||
public void RenamePlaylist(int playlistId, string name) { }
|
||||
|
||||
public void DeletePlaylist(int playlistId) { }
|
||||
|
||||
public void SetPlaylistEntries(int playlistId, IList<RemotePlaylistEntry> entries)
|
||||
{
|
||||
Playlists.First(p => p.Id == playlistId).Entries = entries.ToList();
|
||||
}
|
||||
|
||||
public ERemoteStartResult StartSong(RemoteStartRequest request)
|
||||
{
|
||||
return ERemoteStartResult.Singing;
|
||||
}
|
||||
|
||||
public void SendKey(ERemoteKey key) { }
|
||||
|
||||
public void SendText(string text) { }
|
||||
}
|
||||
|
||||
private readonly CSession _Anna = new CSession { ProfileId = Guid.NewGuid(), ProfileName = "Anna" };
|
||||
private readonly CSession _Ben = new CSession { ProfileId = Guid.NewGuid(), ProfileName = "Ben" };
|
||||
private readonly CSession _Cleo = new CSession { ProfileId = Guid.NewGuid(), ProfileName = "Cleo" };
|
||||
private CFakeRemote _Remote;
|
||||
private CQueueService _Queue;
|
||||
private CancellationTokenSource _Stop;
|
||||
private Task _MainThread;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_Remote = new CFakeRemote();
|
||||
var dispatcher = new CMainThreadDispatcher(TimeSpan.FromSeconds(5));
|
||||
_Queue = new CQueueService(_Remote, dispatcher, new CWebSettingsStore(null), new CSongLibrary(_Remote, dispatcher), new CLiveEvents());
|
||||
_Stop = new CancellationTokenSource();
|
||||
_MainThread = Task.Run(async () =>
|
||||
{
|
||||
while (!_Stop.IsCancellationRequested)
|
||||
{
|
||||
dispatcher.ProcessPending();
|
||||
await Task.Delay(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
_Stop.Cancel();
|
||||
_MainThread.Wait();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFairOrder()
|
||||
{
|
||||
_Add(1, _Anna);
|
||||
_Add(2, _Anna);
|
||||
_Add(3, _Anna);
|
||||
_Add(4, _Ben);
|
||||
_Add(5, _Ben);
|
||||
var queue = _Add(6, _Cleo);
|
||||
|
||||
Assert.That(_Requesters(queue), Is.EqualTo(new[] { "Anna", "Ben", "Cleo", "Anna", "Ben", "Anna" }));
|
||||
Assert.That(queue.Select(e => e.Song.Id), Is.EqualTo(new[] { 1, 4, 6, 2, 5, 3 }));
|
||||
Assert.That(queue.Select(e => e.Position), Is.EqualTo(Enumerable.Range(0, 6)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddMany()
|
||||
{
|
||||
_Add(1, _Ben);
|
||||
var queue = _Queue.AddManyAsync(new[] { 2, 3, 4 }.Select(id => new RemotePlaylistEntry { SongId = id }).ToList(), _Anna).Result;
|
||||
|
||||
Assert.That(_Requesters(queue), Is.EqualTo(new[] { "Ben", "Anna", "Anna", "Anna" }));
|
||||
Assert.That(_Requesters(_Add(5, _Ben)), Is.EqualTo(new[] { "Ben", "Anna", "Anna", "Ben", "Anna" }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPlaylistIsUpdated()
|
||||
{
|
||||
_Add(7, _Anna);
|
||||
_Add(8, _Ben);
|
||||
|
||||
var playlist = _Remote.Playlists.Single(p => p.Name == "WebApp Queue");
|
||||
Assert.That(playlist.Entries.Select(e => e.SongId), Is.EqualTo(new[] { 7, 8 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSongsAddedInTheGame()
|
||||
{
|
||||
_Add(1, _Anna);
|
||||
_Remote.Playlists[0].Entries.Add(new RemotePlaylistEntry { SongId = 9 });
|
||||
|
||||
var queue = _Add(2, _Anna);
|
||||
Assert.That(queue.Select(e => e.Song.Id), Is.EqualTo(new[] { 1, 9, 2 }));
|
||||
Assert.That(queue[1].RequestedBy, Is.Null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestOnlyOwnerOrManagerMayRemove()
|
||||
{
|
||||
var entry = _Add(1, _Anna)[0];
|
||||
|
||||
Exception error = null;
|
||||
try
|
||||
{
|
||||
_Queue.RemoveAsync(entry.Id, _Ben, false).Wait();
|
||||
}
|
||||
catch (AggregateException e)
|
||||
{
|
||||
error = e.InnerException;
|
||||
}
|
||||
|
||||
Assert.That(error, Is.InstanceOf<CQueueService.CForbiddenException>());
|
||||
Assert.That(_Queue.GetAsync().Result, Has.Count.EqualTo(1));
|
||||
|
||||
Assert.That(_Queue.RemoveAsync(entry.Id, _Ben, true).Result, Is.Empty);
|
||||
_Add(2, _Anna);
|
||||
Assert.That(_Queue.RemoveAsync(_Queue.GetAsync().Result[0].Id, _Anna, false).Result, Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMove()
|
||||
{
|
||||
_Add(1, _Anna);
|
||||
_Add(2, _Ben);
|
||||
var queue = _Add(3, _Cleo);
|
||||
|
||||
queue = _Queue.MoveAsync(queue[2].Id, 0).Result;
|
||||
Assert.That(queue.Select(e => e.Song.Id), Is.EqualTo(new[] { 3, 1, 2 }));
|
||||
queue = _Queue.MoveAsync(queue[0].Id, 99).Result;
|
||||
Assert.That(queue.Select(e => e.Song.Id), Is.EqualTo(new[] { 1, 2, 3 }));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestRemoveSung()
|
||||
{
|
||||
_Add(1, _Anna);
|
||||
_Add(2, _Ben);
|
||||
|
||||
var queue = _Queue.RemoveSungAsync(1).Result;
|
||||
Assert.That(queue.Select(e => e.Song.Id), Is.EqualTo(new[] { 2 }));
|
||||
Assert.That(_Queue.RemoveSungAsync(5).Result, Has.Count.EqualTo(1));
|
||||
}
|
||||
|
||||
private IList<QueueEntryDto> _Add(int songId, CSession session)
|
||||
{
|
||||
return _Queue.AddAsync(songId, ESongGameMode.Normal, ESongAudioMode.Normal, null, session).Result;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> _Requesters(IEnumerable<QueueEntryDto> queue)
|
||||
{
|
||||
return queue.Select(e => e.RequestedBy?.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using NUnit.Framework;
|
||||
using VocaluxeWeb.Services;
|
||||
|
||||
namespace Tests.VocaluxeWeb
|
||||
{
|
||||
[TestFixture]
|
||||
public class CUserAgentTest
|
||||
{
|
||||
[TestCase("Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile/15E148 Safari/604.1", "iPhone · Safari")]
|
||||
[TestCase("Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Mobile Safari/537.36", "Android phone · Chrome")]
|
||||
[TestCase("Mozilla/5.0 (Linux; Android 14; SM-X710) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/26.0 Chrome/122.0.0.0 Safari/537.36", "Android tablet · Samsung Internet")]
|
||||
[TestCase("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0", "Windows · Edge")]
|
||||
[TestCase("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:132.0) Gecko/20100101 Firefox/132.0", "Mac · Firefox")]
|
||||
[TestCase("curl/8.7.1", "curl/8.7.1")]
|
||||
[TestCase("", null)]
|
||||
[TestCase(null, null)]
|
||||
public void TestDescribe(string userAgent, string expected)
|
||||
{
|
||||
Assert.That(CUserAgent.Describe(userAgent), Is.EqualTo(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using VocaluxeWeb.Contracts;
|
||||
using VocaluxeWeb.Remote;
|
||||
using VocaluxeWeb.Services;
|
||||
|
||||
namespace Tests.VocaluxeWeb
|
||||
{
|
||||
[TestFixture]
|
||||
public class CWebSettingsTest
|
||||
{
|
||||
private string _Path;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_Path = Path.Combine(Path.GetTempPath(), "VocaluxeWebTest_" + Guid.NewGuid().ToString("N"), "WebSettings.json");
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
var directory = Path.GetDirectoryName(_Path);
|
||||
if (Directory.Exists(directory))
|
||||
{
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAdminHasAllPermissions()
|
||||
{
|
||||
var settings = new CWebSettings();
|
||||
settings.GuestPermissions.Clear();
|
||||
settings.PlayerPermissions.Clear();
|
||||
var all = Enum.GetValues(typeof(EPermission)).Cast<EPermission>().ToList();
|
||||
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Admin), Is.EquivalentTo(all));
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Guest), Is.Empty);
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Player), Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDefaults()
|
||||
{
|
||||
var settings = new CWebSettings();
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Guest), Is.EquivalentTo(new[] { EPermission.AddToQueue }));
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Player), Does.Contain(EPermission.AddToQueue));
|
||||
Assert.That(settings.GetPermissions(ERemoteRole.Player), Does.Not.Contain(EPermission.EditAllProfiles));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStoreSavesAndLoads()
|
||||
{
|
||||
var store = new CWebSettingsStore(_Path);
|
||||
store.Update(s =>
|
||||
{
|
||||
s.AllowProfileCreation = false;
|
||||
s.QueuePlaylistName = "Party queue";
|
||||
s.GuestPermissions.Add(EPermission.UseKeyboard);
|
||||
});
|
||||
|
||||
var loaded = new CWebSettingsStore(_Path).Current;
|
||||
Assert.That(loaded.AllowProfileCreation, Is.False);
|
||||
Assert.That(loaded.QueuePlaylistName, Is.EqualTo("Party queue"));
|
||||
Assert.That(loaded.GetPermissions(ERemoteRole.Guest), Does.Contain(EPermission.UseKeyboard));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCurrentIsACopy()
|
||||
{
|
||||
var store = new CWebSettingsStore(_Path);
|
||||
store.Current.GuestPermissions.Add(EPermission.DeletePlaylists);
|
||||
Assert.That(store.Current.GuestPermissions, Does.Not.Contain(EPermission.DeletePlaylists));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestBrokenFile()
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_Path));
|
||||
File.WriteAllText(_Path, "{ broken");
|
||||
var store = new CWebSettingsStore(_Path);
|
||||
Assert.That(store.Current.QueuePlaylistName, Is.EqualTo("WebApp Queue"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFileWithRemovedSettings()
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(_Path));
|
||||
File.WriteAllText(_Path, "{ \"RequireJoinToken\": true, \"JoinToken\": \"abc\", \"QueuePlaylistName\": \"Party\" }");
|
||||
Assert.That(new CWebSettingsStore(_Path).Current.QueuePlaylistName, Is.EqualTo("Party"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,6 @@ MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Vocaluxe", "Vocaluxe\Vocaluxe.csproj", "{2A1E0F2D-5392-4BB7-B0A1-A9DFA13E79FF}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41} = {7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9} = {55F89808-4E79-4FFE-BC13-48258913F5C9}
|
||||
{6F3E1874-F28A-40E9-AFBD-31934D593679} = {6F3E1874-F28A-40E9-AFBD-31934D593679}
|
||||
{9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53} = {9D4F1C27-3B8E-4A62-B5D0-7E1A2C6F9B53}
|
||||
{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC} = {D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}
|
||||
@@ -25,7 +24,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeChallenge", "Party
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeTournament", "PartyModes\PartyModeTournament\PartyModeTournament.csproj", "{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebserverInitalConfig", "WebserverInitalConfig\WebserverInitalConfig.csproj", "{55F89808-4E79-4FFE-BC13-48258913F5C9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VocaluxeWeb", "VocaluxeWeb\VocaluxeWeb.csproj", "{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PartyModeRuleRoulette", "PartyModes\PartyModeRuleRoulette\PartyModeRuleRoulette.csproj", "{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}"
|
||||
EndProject
|
||||
@@ -169,22 +168,6 @@ Global
|
||||
{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU
|
||||
{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU
|
||||
{3C7D2E51-8A64-4F0B-9E2A-6B1D4C8F7A20}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x64.ActiveCfg = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugLinux|x86.ActiveCfg = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.ActiveCfg = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x64.Build.0 = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x86.ActiveCfg = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.DebugWin|x86.Build.0 = Debug|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x64.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x64.Build.0 = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x86.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.InstallerWin|x86.Build.0 = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x64.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseLinux|x86.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x64.Build.0 = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.ActiveCfg = Release|Any CPU
|
||||
{55F89808-4E79-4FFE-BC13-48258913F5C9}.ReleaseWin|x86.Build.0 = Release|Any CPU
|
||||
{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
|
||||
{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}.DebugLinux|x64.Build.0 = DebugLinux|Any CPU
|
||||
{2E6A9B48-71C3-4D05-8F2B-C4A7D19E6E3F}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU
|
||||
@@ -265,6 +248,22 @@ Global
|
||||
{7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU
|
||||
{7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU
|
||||
{7B2E4A19-5C3D-4E8F-A16B-2D9C0F3E8B41}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugLinux|x64.ActiveCfg = DebugLinux|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugLinux|x86.ActiveCfg = DebugLinux|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugWin|x64.Build.0 = DebugWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.DebugWin|x86.Build.0 = DebugWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.InstallerWin|x64.ActiveCfg = InstallerWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.InstallerWin|x64.Build.0 = InstallerWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.InstallerWin|x86.ActiveCfg = InstallerWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.InstallerWin|x86.Build.0 = InstallerWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseLinux|x64.ActiveCfg = ReleaseLinux|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseLinux|x86.ActiveCfg = ReleaseLinux|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU
|
||||
{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Vocaluxe.Base.Server;
|
||||
using Vocaluxe.Base.Web;
|
||||
using Vocaluxe.Lib.Input;
|
||||
using Vocaluxe.Lib.Input.WiiMote;
|
||||
using VocaluxeLib;
|
||||
@@ -38,7 +38,7 @@ namespace Vocaluxe.Base
|
||||
|
||||
_AddController(new CWiiMote());
|
||||
_AddController(new CGamePad());
|
||||
_AddController(CVocaluxeServer.Controller);
|
||||
_AddController(CWebServer.Controller);
|
||||
}
|
||||
|
||||
private static void _AddController(IController controller)
|
||||
|
||||
@@ -47,6 +47,14 @@ namespace Vocaluxe.Base
|
||||
public static float ZOffset { get; private set; }
|
||||
|
||||
public static IMenu CurrentScreen { get; private set; }
|
||||
public static EScreen CurrentScreenType
|
||||
{
|
||||
get
|
||||
{
|
||||
var id = _Screens.IndexOf(CurrentScreen);
|
||||
return (EScreen)id;
|
||||
}
|
||||
}
|
||||
|
||||
public static IMenu NextScreen { get; private set; }
|
||||
public static EScreen NextScreenType
|
||||
@@ -89,6 +97,7 @@ namespace Vocaluxe.Base
|
||||
_Screens.Add(new CScreenStatisticsDetail());
|
||||
_Screens.Add(new CScreenJukebox());
|
||||
_Screens.Add(new CScreenJukeboxPlayer());
|
||||
_Screens.Add(new CScreenWebQueue());
|
||||
|
||||
Debug.Assert(_Screens.Count == (int)EScreen.CountEntry, "Screen list and screens enum do not match");
|
||||
|
||||
|
||||
@@ -135,6 +135,7 @@ namespace Vocaluxe.Base
|
||||
public const string FolderNameThemeFonts = "Fonts";
|
||||
public const string FolderNameScreens = "Screens";
|
||||
public const string FolderNamePhotos = "Photos";
|
||||
public const string FolderNameWebsite = "Website";
|
||||
public const string FolderNameSounds = "Sounds";
|
||||
public const string FolderNameLanguages = "Languages";
|
||||
public const string FolderNameScreenshots = "Screenshots";
|
||||
|
||||
@@ -1,629 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Channels;
|
||||
using System.ServiceModel.Web;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
class CWebservice : ICWebservice
|
||||
{
|
||||
private static Guid _GetSession()
|
||||
{
|
||||
var sessionKey = Guid.Empty;
|
||||
var sessionHeader =
|
||||
((HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties["httpRequest"]).Headers["session"];
|
||||
if (string.IsNullOrEmpty(sessionHeader))
|
||||
{
|
||||
return sessionKey;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
sessionKey = Guid.Parse(sessionHeader);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
CSessionControl.ResetSessionTimeout(sessionKey);
|
||||
return sessionKey;
|
||||
}
|
||||
|
||||
public void SendKeyEvent(string key)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.UseKeyboard))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
CVocaluxeServer.DoTask(CVocaluxeServer.SendKeyEvent, key);
|
||||
}
|
||||
|
||||
public void SendKeyStringEvent(string keyString, bool isShiftPressed = false, bool isAltPressed = false, bool isCtrlPressed = false)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.UseKeyboard))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CVocaluxeServer.DoTask(CVocaluxeServer.SendKeyStringEvent, keyString, isShiftPressed, isAltPressed, isCtrlPressed);
|
||||
}
|
||||
|
||||
#region profile
|
||||
public Guid GetOwnProfileId()
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
if (sessionKey == Guid.Empty)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session";
|
||||
}
|
||||
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
var profileId = CSessionControl.GetUserIdFromSession(sessionKey);
|
||||
if (profileId == Guid.Empty)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session";
|
||||
}
|
||||
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
return profileId;
|
||||
}
|
||||
|
||||
public void SendProfile(SProfileData profile)
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
|
||||
if (profile.ProfileId != Guid.Empty) //Guid.Empty is the id for a new profile
|
||||
{
|
||||
if (CSessionControl.GetUserIdFromSession(sessionKey) != profile.ProfileId
|
||||
&& !_CheckRight(EUserRights.EditAllProfiles))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CVocaluxeServer.DoTask(CVocaluxeServer.SendProfileData, profile);
|
||||
}
|
||||
|
||||
public SProfileData GetProfile(Guid profileId)
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
if (CSessionControl.GetUserIdFromSession(sessionKey) == profileId || _CheckRight(EUserRights.ViewOtherProfiles))
|
||||
{
|
||||
var isReadonly = !CSessionControl.RequestRight(sessionKey, EUserRights.EditAllProfiles) &&
|
||||
CSessionControl.GetUserIdFromSession(sessionKey) != profileId;
|
||||
|
||||
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetProfileData, profileId, isReadonly);
|
||||
}
|
||||
|
||||
return new SProfileData();
|
||||
}
|
||||
|
||||
public SProfileData[] GetProfileList()
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetProfileList);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region photo
|
||||
public void SendPhoto(SPhotoData photo)
|
||||
{
|
||||
if (_CheckRight(EUserRights.UploadPhotos))
|
||||
{
|
||||
CVocaluxeServer.DoTask(CVocaluxeServer.SendPhoto, photo);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region website
|
||||
public Guid Login(string username, string password)
|
||||
{
|
||||
var sessionId = CSessionControl.OpenSession(username, password);
|
||||
if (sessionId == Guid.Empty)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = "Wrong username or password";
|
||||
}
|
||||
}
|
||||
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
public void Logout()
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
CSessionControl.InvalidateSessionById(sessionKey);
|
||||
}
|
||||
|
||||
public Stream Index()
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
|
||||
}
|
||||
|
||||
return new MemoryStream(CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "index.html"));
|
||||
}
|
||||
|
||||
public Stream GetJsFile(string filename)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "text/javascript";
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddHours(4).ToString("r"));
|
||||
}
|
||||
|
||||
var data = CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "js/" + filename);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream GetCssFile(string filename)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "text/css";
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddHours(4).ToString("r"));
|
||||
}
|
||||
|
||||
var data = CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "css/" + filename);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream GetCssImageFile(string filename)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "image/png";
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddYears(1).ToString("r"));
|
||||
}
|
||||
|
||||
var data = CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "css\\images\\" + filename);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream GetImgFile(string filename)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "image/png";
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddYears(1).ToString("r"));
|
||||
}
|
||||
|
||||
var data = CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "img/" + filename);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Stream GetLocaleFile(string filename)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "text/javascript";
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddHours(4).ToString("r"));
|
||||
}
|
||||
|
||||
var data = CVocaluxeServer.DoTask(CVocaluxeServer.GetSiteFile, "locales/" + filename);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
return new MemoryStream(data);
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public CBase64Image GetDelayedImage(string id)
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetDelayedImage, id);
|
||||
}
|
||||
|
||||
public bool IsServerOnline()
|
||||
{
|
||||
_GetSession();
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetServerVersion()
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetServerVersion);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region songs
|
||||
public SSongInfo GetSong(int songId)
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetSong, songId);
|
||||
}
|
||||
|
||||
public int GetCurrentSongId()
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetCurrentSongId);
|
||||
}
|
||||
|
||||
public SSongInfo[] GetAllSongs()
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetAllSongs);
|
||||
}
|
||||
|
||||
public Stream GetMp3File(int songId)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.LastModified = DateTime.UtcNow;
|
||||
WebOperationContext.Current.OutgoingResponse.Headers.Add(
|
||||
HttpResponseHeader.Expires,
|
||||
DateTime.UtcNow.AddYears(1).ToString("r"));
|
||||
}
|
||||
|
||||
|
||||
var path = CVocaluxeServer.DoTask(CVocaluxeServer.GetMp3Path, songId);
|
||||
path = path.Replace("..", "");
|
||||
|
||||
|
||||
if (!File.Exists(path)
|
||||
|| !(path.EndsWith(".mp3", StringComparison.InvariantCulture)
|
||||
|| path.EndsWith(".ogg", StringComparison.InvariantCulture)
|
||||
|| path.EndsWith(".wav", StringComparison.InvariantCulture)
|
||||
|| path.EndsWith(".webm", StringComparison.InvariantCulture)))
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
if (path.EndsWith(".mp3", StringComparison.InvariantCulture))
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/mpeg";
|
||||
}
|
||||
else if (path.EndsWith(".ogg", StringComparison.InvariantCulture))
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/ogg";
|
||||
}
|
||||
else if (path.EndsWith(".wav", StringComparison.InvariantCulture))
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/wav";
|
||||
}
|
||||
else if (path.EndsWith(".webm", StringComparison.InvariantCulture))
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.ContentType = "audio/webm";
|
||||
}
|
||||
}
|
||||
|
||||
return File.OpenRead(path);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region playlist
|
||||
public SPlaylistData[] GetPlaylists()
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetPlaylists);
|
||||
}
|
||||
|
||||
public SPlaylistData GetPlaylist(int playlistId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetPlaylist, playlistId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
|
||||
return new SPlaylistData();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.AddSongToPlaylist))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CVocaluxeServer.DoTaskWithoutReturn(CVocaluxeServer.AddSongToPlaylist, songId, playlistId, allowDuplicates);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSongFromPlaylist(int position, int playlistId, int songId)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.RemoveSongsFromPlaylists))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CVocaluxeServer.DoTaskWithoutReturn(CVocaluxeServer.RemoveSongFromPlaylist, position, playlistId, songId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveSongInPlaylist(int newPosition, int playlistId, int songId)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.ReorderPlaylists))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CVocaluxeServer.DoTaskWithoutReturn(CVocaluxeServer.MoveSongInPlaylist, newPosition, playlistId, songId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool PlaylistContainsSong(int songId, int playlistId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.PlaylistContainsSong, songId, playlistId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public SPlaylistSongInfo[] GetPlaylistSongs(int playlistId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetPlaylistSongs, playlistId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
|
||||
return new SPlaylistSongInfo[0];
|
||||
}
|
||||
}
|
||||
|
||||
public void RemovePlaylist(int playlistId)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.DeletePlaylists))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
CVocaluxeServer.DoTaskWithoutReturn(CVocaluxeServer.RemovePlaylist, playlistId);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int AddPlaylist(string playlistName)
|
||||
{
|
||||
if (!_CheckRight(EUserRights.CreatePlaylists))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.AddPlaylist, playlistName);
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = e.Message;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region user management
|
||||
public int GetUserRole(Guid profileId)
|
||||
{
|
||||
return CVocaluxeServer.DoTask(CVocaluxeServer.GetUserRole, profileId);
|
||||
}
|
||||
|
||||
public void SetUserRole(Guid profileId, int userRole)
|
||||
{
|
||||
if (_CheckRight(EUserRights.EditAllProfiles))
|
||||
{
|
||||
CVocaluxeServer.DoTaskWithoutReturn(CVocaluxeServer.SetUserRole, profileId, userRole);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasUserRight(int right)
|
||||
{
|
||||
return _CheckRightWithNoErrorMessage((EUserRights)right);
|
||||
}
|
||||
|
||||
private static bool _CheckRight(EUserRights requestedRight)
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
|
||||
if (sessionKey == Guid.Empty)
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = "No session";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CSessionControl.RequestRight(sessionKey, requestedRight))
|
||||
{
|
||||
if (WebOperationContext.Current != null)
|
||||
{
|
||||
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Forbidden;
|
||||
WebOperationContext.Current.OutgoingResponse.StatusDescription = "Not allowed";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool _CheckRightWithNoErrorMessage(EUserRights requestedRight)
|
||||
{
|
||||
var sessionKey = _GetSession();
|
||||
|
||||
if (sessionKey == Guid.Empty)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CSessionControl.RequestRight(sessionKey, requestedRight))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.ServiceModel;
|
||||
using System.ServiceModel.Web;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
[ServiceContract]
|
||||
public interface ICWebservice
|
||||
{
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendKeyEvent?key={key}")]
|
||||
void SendKeyEvent(string key);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendKeyStringEvent?keyString={keyString}&shift={isShiftPressed}&alt={isAltPressed}&ctrl={isCtrlPressed}")]
|
||||
void SendKeyStringEvent(string keyString, bool isShiftPressed = false, bool isAltPressed = false, bool isCtrlPressed = false);
|
||||
|
||||
#region profile
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getOwnProfileId")]
|
||||
Guid GetOwnProfileId();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "POST",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendProfile")]
|
||||
void SendProfile(SProfileData profile);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getProfile?profileId={profileId}")]
|
||||
SProfileData GetProfile(Guid profileId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getProfileList")]
|
||||
SProfileData[] GetProfileList();
|
||||
#endregion
|
||||
|
||||
#region photo
|
||||
[OperationContract, WebInvoke(Method = "POST",
|
||||
RequestFormat = WebMessageFormat.Json,
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/sendPhoto")]
|
||||
void SendPhoto(SPhotoData photo);
|
||||
#endregion
|
||||
|
||||
#region website
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/login?username={username}&password={password}")]
|
||||
Guid Login(string username, string password);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/logout")]
|
||||
void Logout();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "")]
|
||||
Stream Index();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/js/{filename}")]
|
||||
Stream GetJsFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/css/{filename}")]
|
||||
Stream GetCssFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/css/images/{filename}")]
|
||||
Stream GetCssImageFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/img/{filename}")]
|
||||
Stream GetImgFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/locales/{filename}")]
|
||||
Stream GetLocaleFile(String filename);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/delayedImage?id={id}")]
|
||||
CBase64Image GetDelayedImage(String id);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/isServerOnline")]
|
||||
bool IsServerOnline();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getServerVersion")]
|
||||
String GetServerVersion();
|
||||
#endregion
|
||||
|
||||
#region songs
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getSong?songId={songId}")]
|
||||
SSongInfo GetSong(int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getCurrentSongId")]
|
||||
int GetCurrentSongId();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getAllSongs")]
|
||||
SSongInfo[] GetAllSongs();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getMp3?songId={songId}")]
|
||||
Stream GetMp3File(int songId);
|
||||
#endregion
|
||||
|
||||
#region playlist
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylists")]
|
||||
SPlaylistData[] GetPlaylists();
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylist?id={playlistId}")]
|
||||
SPlaylistData GetPlaylist(int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/addSongToPlaylist?songId={songId}&playlistId={playlistId}&duplicates={allowDuplicates}")]
|
||||
void AddSongToPlaylist(int songId, int playlistId, bool allowDuplicates);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/removeSongFromPlaylist?position={position}&playlistId={playlistId}&songId={songId}")]
|
||||
void RemoveSongFromPlaylist(int position, int playlistId, int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/moveSongInPlaylist?newPosition={newPosition}&playlistId={playlistId}&songId={songId}")]
|
||||
void MoveSongInPlaylist(int newPosition, int playlistId, int songId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/playlistContainsSong?songId={songId}&playlistId={playlistId}")]
|
||||
bool PlaylistContainsSong(int songId, int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getPlaylistSongs?playlistId={playlistId}")]
|
||||
SPlaylistSongInfo[] GetPlaylistSongs(int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/removePlaylist?playlistId={playlistId}")]
|
||||
void RemovePlaylist(int playlistId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/addPlaylist?playlistName={playlistName}")]
|
||||
int AddPlaylist(string playlistName);
|
||||
#endregion
|
||||
|
||||
#region user management
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/getUserRole?profileId={profileId}")]
|
||||
int GetUserRole(Guid profileId);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/setUserRole?profileId={profileId}&userRole={userRole}")]
|
||||
void SetUserRole(Guid profileId, int userRole);
|
||||
|
||||
[OperationContract, WebInvoke(Method = "GET",
|
||||
ResponseFormat = WebMessageFormat.Json,
|
||||
UriTemplate = "/hasUserRight?right={right}")]
|
||||
bool HasUserRight(int right);
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Timers;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
static class CSessionControl
|
||||
{
|
||||
private static readonly Dictionary<Guid, CSession> _ActiveSessions;
|
||||
private const int _UserTimeoutCheckIntervall = 120000;
|
||||
private const int _UserTimeout = 120000;
|
||||
|
||||
static CSessionControl()
|
||||
{
|
||||
_ActiveSessions = new Dictionary<Guid, CSession>();
|
||||
var timer = new Timer(_UserTimeoutCheckIntervall) { AutoReset = true, Enabled = true };
|
||||
timer.Elapsed += _CheckForUserTimeouts;
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private static void _CheckForUserTimeouts(object sender, ElapsedEventArgs e)
|
||||
{
|
||||
var sessionIdsToRemove = _ActiveSessions.Where(pair => (DateTime.Now - pair.Value.LastSeen).TotalMilliseconds > _UserTimeout)
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
|
||||
foreach (var sessionToRemove in sessionIdsToRemove)
|
||||
{
|
||||
InvalidateSessionById(sessionToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
public static Guid OpenSession(string userName, string password)
|
||||
{
|
||||
if (!_ValidateUserAndPassword(userName, password))
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
var newId = Guid.NewGuid();
|
||||
var id = _GetProfileIdFormUsername(userName);
|
||||
var roles = _GetUserRoles(id);
|
||||
var session = new CSession(newId, id, roles);
|
||||
//InvalidateSessions(id);
|
||||
_ActiveSessions.Add(newId, session);
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
private static bool _ValidateUserAndPassword(string userName, string password)
|
||||
{
|
||||
return CVocaluxeServer.ValidatePassword(_GetProfileIdFormUsername(userName), password);
|
||||
}
|
||||
|
||||
private static Guid _GetProfileIdFormUsername(string username)
|
||||
{
|
||||
return CVocaluxeServer.GetUserIdFromUsername(username);
|
||||
}
|
||||
|
||||
private static EUserRoles _GetUserRoles(Guid profileId)
|
||||
{
|
||||
return (EUserRoles)CVocaluxeServer.GetUserRole(profileId);
|
||||
}
|
||||
|
||||
internal static void InvalidateSessionByProfile(Guid profileId)
|
||||
{
|
||||
foreach (var s in (from kv in _ActiveSessions
|
||||
where kv.Value.ProfileId == profileId
|
||||
select kv).ToList())
|
||||
{
|
||||
_ActiveSessions.Remove(s.Key);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void InvalidateSessionById(Guid sessionId)
|
||||
{
|
||||
if (_ActiveSessions.ContainsKey(sessionId))
|
||||
{
|
||||
_ActiveSessions.Remove(sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool RequestRight(Guid sessionId, EUserRights requestedRight)
|
||||
{
|
||||
return CUserRoleControl.GetUserRightsFromUserRole(_ActiveSessions[sessionId].Roles)
|
||||
.HasFlag(requestedRight);
|
||||
}
|
||||
|
||||
internal static Guid GetUserIdFromSession(Guid sessionId)
|
||||
{
|
||||
if (!_ActiveSessions.ContainsKey(sessionId))
|
||||
{
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
return _ActiveSessions[sessionId].ProfileId;
|
||||
}
|
||||
|
||||
internal static void ResetSessionTimeout(Guid sessionId)
|
||||
{
|
||||
CSession value;
|
||||
if (_ActiveSessions.TryGetValue(sessionId, out value))
|
||||
{
|
||||
value.LastSeen = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
[Flags]
|
||||
enum EUserRights
|
||||
{
|
||||
None = 0,
|
||||
EditAllProfiles = 1,
|
||||
UploadPhotos = 2,
|
||||
ViewOtherProfiles = 4,
|
||||
UseKeyboard = 8,
|
||||
ReorderPlaylists = 16,
|
||||
AddSongToPlaylist = 32,
|
||||
CreatePlaylists = 64,
|
||||
DeletePlaylists = 128,
|
||||
RemoveSongsFromPlaylists = 256
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
static class CUserRoleControl
|
||||
{
|
||||
private static readonly Dictionary<EUserRoles, EUserRights> _RoleRightsMapping = new Dictionary<EUserRoles, EUserRights>
|
||||
{
|
||||
{
|
||||
EUserRoles.TR_USERROLE_ADMIN,
|
||||
EUserRights.EditAllProfiles |
|
||||
EUserRights.UploadPhotos |
|
||||
EUserRights.ViewOtherProfiles |
|
||||
EUserRights.UseKeyboard |
|
||||
EUserRights.AddSongToPlaylist |
|
||||
EUserRights.ReorderPlaylists |
|
||||
EUserRights.CreatePlaylists |
|
||||
EUserRights.DeletePlaylists |
|
||||
EUserRights.RemoveSongsFromPlaylists
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_GUEST,
|
||||
EUserRights.None
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_NORMAL,
|
||||
EUserRights.UploadPhotos |
|
||||
EUserRights.ViewOtherProfiles
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_KEYBOARDUSER,
|
||||
EUserRights.UseKeyboard
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_ADDSONGSUSER,
|
||||
EUserRights.AddSongToPlaylist
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_PLAYLISTEDITOR,
|
||||
EUserRights.AddSongToPlaylist |
|
||||
EUserRights.ReorderPlaylists |
|
||||
EUserRights.CreatePlaylists |
|
||||
EUserRights.DeletePlaylists |
|
||||
EUserRights.RemoveSongsFromPlaylists
|
||||
},
|
||||
{
|
||||
EUserRoles.TR_USERROLE_PROFILEEDITOR,
|
||||
EUserRights.EditAllProfiles
|
||||
}
|
||||
};
|
||||
|
||||
internal static EUserRights GetUserRightsFromUserRole(EUserRoles userRole)
|
||||
{
|
||||
return _RoleRightsMapping.Where(role => userRole.HasFlag(role.Key))
|
||||
.Select(role => role.Value)
|
||||
.Aggregate(EUserRights.None, (current, r) => current | r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
[Flags]
|
||||
enum EUserRoles
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
TR_USERROLE_GUEST = 0,
|
||||
TR_USERROLE_NORMAL = 1,
|
||||
TR_USERROLE_ADMIN = 2,
|
||||
TR_USERROLE_KEYBOARDUSER = 4,
|
||||
TR_USERROLE_ADDSONGSUSER = 8,
|
||||
TR_USERROLE_PLAYLISTEDITOR = 16,
|
||||
TR_USERROLE_PROFILEEDITOR = 32
|
||||
// ReSharper restore InconsistentNaming
|
||||
}
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
{
|
||||
public struct SLoginData
|
||||
{
|
||||
public byte[] Sha256;
|
||||
}
|
||||
|
||||
public struct SPicture
|
||||
{
|
||||
public int Width;
|
||||
public int Height;
|
||||
public byte[] Data;
|
||||
}
|
||||
|
||||
public struct SProfile
|
||||
{
|
||||
public SPicture Avatar;
|
||||
public string PlayerName;
|
||||
public int Difficulty;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public struct SProfileData
|
||||
{
|
||||
[DataMember]
|
||||
public CBase64Image Avatar;
|
||||
[DataMember]
|
||||
public string PlayerName;
|
||||
[DataMember]
|
||||
public int Type;
|
||||
[DataMember]
|
||||
public int Difficulty;
|
||||
[DataMember]
|
||||
public Guid ProfileId;
|
||||
[DataMember]
|
||||
public bool IsEditable;
|
||||
[DataMember]
|
||||
public string Password;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public struct SPhotoData
|
||||
{
|
||||
[DataMember]
|
||||
public CBase64Image Photo;
|
||||
//Add infomation about the user who took this image??
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class CBase64Image
|
||||
{
|
||||
// ReSharper disable InconsistentNaming
|
||||
[DataMember]
|
||||
private string base64Data = "";
|
||||
[DataMember]
|
||||
private string imageId = "";
|
||||
// ReSharper restore InconsistentNaming
|
||||
|
||||
public CBase64Image(Image img, ImageFormat format)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
img.Save(ms, format);
|
||||
var formatString = ImageCodecInfo.GetImageEncoders().FirstOrDefault(x => x.FormatID == format.Guid).FilenameExtension.Replace("*.", "").ToLower();
|
||||
base64Data = "data:image/" + formatString + ";base64," + Convert.ToBase64String(ms.ToArray());
|
||||
}
|
||||
|
||||
public CBase64Image(string imageId)
|
||||
{
|
||||
this.imageId = imageId;
|
||||
}
|
||||
|
||||
public Image GetImage()
|
||||
{
|
||||
var onlyBase64Data = base64Data.Substring(base64Data.IndexOf(";base64,") + ";base64,".Length);
|
||||
var imageData = Convert.FromBase64String(onlyBase64Data);
|
||||
var ms = new MemoryStream(imageData, 0, imageData.Length);
|
||||
ms.Write(imageData, 0, imageData.Length);
|
||||
var image = Image.FromStream(ms, true);
|
||||
return image;
|
||||
}
|
||||
|
||||
public string GetImageType()
|
||||
{
|
||||
var match = Regex.Match(base64Data, "(?<=data:image/)[a-zA-Z]+(?=;base64)");
|
||||
return match.Success ? match.Groups[0].Value : "";
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public struct SSongInfo
|
||||
{
|
||||
[DataMember]
|
||||
public string Title;
|
||||
[DataMember]
|
||||
public string Artist;
|
||||
[DataMember]
|
||||
public CBase64Image Cover;
|
||||
[DataMember]
|
||||
public string Genre { get; set; }
|
||||
[DataMember]
|
||||
public string Language { get; set; }
|
||||
[DataMember]
|
||||
public string Year { get; set; }
|
||||
[DataMember]
|
||||
public bool IsDuet { get; set; }
|
||||
[DataMember]
|
||||
public int SongId { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public struct SPlaylistSongInfo
|
||||
{
|
||||
[DataMember]
|
||||
public SSongInfo Song;
|
||||
[DataMember]
|
||||
public int PlaylistId;
|
||||
[DataMember]
|
||||
public int PlaylistPosition;
|
||||
[DataMember]
|
||||
public int GameMode;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public struct SPlaylistData
|
||||
{
|
||||
[DataMember]
|
||||
public int PlaylistId;
|
||||
[DataMember]
|
||||
public string PlaylistName;
|
||||
[DataMember]
|
||||
public int SongCount;
|
||||
[DataMember]
|
||||
public string LastChanged;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +1,41 @@
|
||||
#region license
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using Vocaluxe.Lib.Input;
|
||||
|
||||
namespace Vocaluxe.Base.Server
|
||||
namespace Vocaluxe.Base.Web
|
||||
{
|
||||
class CSession
|
||||
/// Key events coming from the WebApp's remote keyboard.
|
||||
class CRemoteKeyboard : CControllerFramework
|
||||
{
|
||||
public Guid Id { get; }
|
||||
|
||||
public Guid ProfileId { get; }
|
||||
|
||||
internal EUserRoles Roles { get; }
|
||||
|
||||
public DateTime LastSeen { get; internal set; }
|
||||
|
||||
public CSession(Guid id, Guid profileId, EUserRoles roles)
|
||||
public override string GetName()
|
||||
{
|
||||
Id = id;
|
||||
ProfileId = profileId;
|
||||
Roles = roles;
|
||||
LastSeen = DateTime.Now;
|
||||
return "WebApp";
|
||||
}
|
||||
|
||||
public override void Connect() { }
|
||||
|
||||
public override void Disconnect() { }
|
||||
|
||||
public override bool IsConnected()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void SetRumble(float duration) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,402 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Lib.Input;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Profile;
|
||||
using VocaluxeLib.Songs;
|
||||
using VocaluxeWeb;
|
||||
using VocaluxeWeb.Remote;
|
||||
|
||||
namespace Vocaluxe.Base.Web
|
||||
{
|
||||
/// Gives the webserver access to the game. Everything except <see cref="Version" />, <see cref="SendKey" /> and <see cref="SendText" /> runs on the main thread.
|
||||
class CVocaluxeRemote : IVocaluxeRemote
|
||||
{
|
||||
private const EUserRole _RoleMask = EUserRole.TR_USERROLE_GUEST | EUserRole.TR_USERROLE_NORMAL | EUserRole.TR_USERROLE_ADMIN;
|
||||
private const string _UploadPrefix = "WebApp_";
|
||||
|
||||
private readonly CControllerFramework _Keyboard;
|
||||
|
||||
public CVocaluxeRemote(CControllerFramework keyboard)
|
||||
{
|
||||
_Keyboard = keyboard;
|
||||
}
|
||||
|
||||
public string Version { get; } = CSettings.FullVersion;
|
||||
|
||||
public bool IsReady => CGraphics.CurrentScreenType != EScreen.Load;
|
||||
|
||||
private void _CheckReady()
|
||||
{
|
||||
if (!IsReady)
|
||||
{
|
||||
throw new TimeoutException("Vocaluxe is still loading");
|
||||
}
|
||||
}
|
||||
|
||||
public RemoteState GetState()
|
||||
{
|
||||
return new RemoteState { Screen = CGraphics.CurrentScreenType.ToString(), SongId = CGame.GetSong()?.Id };
|
||||
}
|
||||
|
||||
#region profiles
|
||||
public IList<RemoteProfile> GetProfiles()
|
||||
{
|
||||
return CProfiles.GetProfiles().Select(p => new RemoteProfile
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.PlayerName,
|
||||
Role = _ToRemoteRole(p.UserRole),
|
||||
Difficulty = (int)p.Difficulty,
|
||||
IsActive = p.Active == EOffOn.TR_CONFIG_ON,
|
||||
AvatarPath = p.Avatar == null || string.IsNullOrEmpty(p.Avatar.FileName) ? null : Path.GetFullPath(p.Avatar.FileName),
|
||||
PinHash = p.PasswordHash,
|
||||
PinSalt = p.PasswordSalt
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public Guid CreateProfile(ProfileChange change)
|
||||
{
|
||||
var profile = new CProfile { Active = EOffOn.TR_CONFIG_ON, UserRole = EUserRole.TR_USERROLE_NORMAL };
|
||||
_Apply(profile, change);
|
||||
CProfiles.AddProfile(profile);
|
||||
CProfiles.Update();
|
||||
return profile.Id;
|
||||
}
|
||||
|
||||
public void UpdateProfile(Guid profileId, ProfileChange change)
|
||||
{
|
||||
var existing = CProfiles.GetProfile(profileId);
|
||||
if (existing == null)
|
||||
{
|
||||
throw new KeyNotFoundException("Profile not found");
|
||||
}
|
||||
|
||||
var profile = new CProfile
|
||||
{
|
||||
Id = existing.Id,
|
||||
FilePath = existing.FilePath,
|
||||
PlayerName = existing.PlayerName,
|
||||
Difficulty = existing.Difficulty,
|
||||
UserRole = existing.UserRole,
|
||||
Active = existing.Active,
|
||||
Avatar = existing.Avatar,
|
||||
PasswordHash = existing.PasswordHash,
|
||||
PasswordSalt = existing.PasswordSalt
|
||||
};
|
||||
_Apply(profile, change);
|
||||
CProfiles.EditProfile(profile);
|
||||
CProfiles.Update();
|
||||
profile.SaveProfile();
|
||||
}
|
||||
|
||||
public void DeleteProfile(Guid profileId)
|
||||
{
|
||||
CProfiles.DeleteProfile(profileId);
|
||||
CProfiles.Update();
|
||||
}
|
||||
|
||||
public IList<RemoteAvatar> GetAvatars()
|
||||
{
|
||||
return (CProfiles.GetAvatars() ?? Enumerable.Empty<CAvatar>())
|
||||
.Where(a => !string.IsNullOrEmpty(a.FileName) && !Path.GetFileName(a.FileName).StartsWith(_UploadPrefix))
|
||||
.OrderBy(a => Path.GetFileName(a.FileName), StringComparer.OrdinalIgnoreCase)
|
||||
.Select(a => new RemoteAvatar { Id = a.Id, Path = Path.GetFullPath(a.FileName) })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static void _Apply(CProfile profile, ProfileChange change)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(change.Name))
|
||||
{
|
||||
profile.PlayerName = change.Name;
|
||||
}
|
||||
|
||||
if (change.Difficulty.HasValue)
|
||||
{
|
||||
profile.Difficulty = (EGameDifficulty)change.Difficulty.Value;
|
||||
}
|
||||
|
||||
if (change.IsActive.HasValue)
|
||||
{
|
||||
profile.Active = change.IsActive.Value ? EOffOn.TR_CONFIG_ON : EOffOn.TR_CONFIG_OFF;
|
||||
}
|
||||
|
||||
if (change.Role.HasValue)
|
||||
{
|
||||
profile.UserRole = (profile.UserRole & ~_RoleMask) | _ToUserRole(change.Role.Value);
|
||||
}
|
||||
|
||||
if (change.ClearPin)
|
||||
{
|
||||
profile.PasswordHash = null;
|
||||
profile.PasswordSalt = null;
|
||||
}
|
||||
else if (change.PinHash != null)
|
||||
{
|
||||
profile.PasswordHash = change.PinHash;
|
||||
profile.PasswordSalt = change.PinSalt;
|
||||
}
|
||||
|
||||
if (change.AvatarId.HasValue)
|
||||
{
|
||||
var avatar = CProfiles.GetAvatars()?.FirstOrDefault(a => a.Id == change.AvatarId.Value);
|
||||
if (avatar != null)
|
||||
{
|
||||
profile.Avatar = avatar;
|
||||
}
|
||||
}
|
||||
|
||||
if (change.AvatarJpeg != null)
|
||||
{
|
||||
var avatar = _CreateAvatar(change.AvatarJpeg);
|
||||
if (avatar != null)
|
||||
{
|
||||
profile.Avatar = avatar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CAvatar _CreateAvatar(byte[] jpeg)
|
||||
{
|
||||
var folder = CConfig.ProfileFolders[0];
|
||||
Directory.CreateDirectory(folder);
|
||||
var fileName = Path.Combine(folder, _UploadPrefix + Guid.NewGuid().ToString("N") + ".jpg");
|
||||
File.WriteAllBytes(fileName, jpeg);
|
||||
|
||||
var avatar = CAvatar.GetAvatar(fileName);
|
||||
if (avatar != null)
|
||||
{
|
||||
CProfiles.AddAvatar(avatar);
|
||||
}
|
||||
|
||||
return avatar;
|
||||
}
|
||||
|
||||
private static ERemoteRole _ToRemoteRole(EUserRole role)
|
||||
{
|
||||
if (role.HasFlag(EUserRole.TR_USERROLE_ADMIN))
|
||||
{
|
||||
return ERemoteRole.Admin;
|
||||
}
|
||||
|
||||
return role.HasFlag(EUserRole.TR_USERROLE_NORMAL) ? ERemoteRole.Player : ERemoteRole.Guest;
|
||||
}
|
||||
|
||||
private static EUserRole _ToUserRole(ERemoteRole role)
|
||||
{
|
||||
switch (role)
|
||||
{
|
||||
case ERemoteRole.Admin:
|
||||
return EUserRole.TR_USERROLE_ADMIN;
|
||||
case ERemoteRole.Player:
|
||||
return EUserRole.TR_USERROLE_NORMAL;
|
||||
default:
|
||||
return EUserRole.TR_USERROLE_GUEST;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region songs
|
||||
public int SongLibraryVersion => CSongs.AllSongs.Count * 2 + (CSongs.SongsLoaded ? 1 : 0);
|
||||
|
||||
public IList<RemoteSong> GetSongs()
|
||||
{
|
||||
_CheckReady();
|
||||
return CSongs.AllSongs.Select(s => new RemoteSong
|
||||
{
|
||||
Id = s.Id,
|
||||
Title = s.Title,
|
||||
Artist = s.Artist,
|
||||
Year = s.Year,
|
||||
Languages = s.Languages.ToList(),
|
||||
Genres = s.Genres.ToList(),
|
||||
Editions = s.Editions.ToList(),
|
||||
IsDuet = s.IsDuet,
|
||||
GameModes = s.AvailableGameModes.Select(m => (int)m).ToList(),
|
||||
AudioModes = _GetAudioModes(s),
|
||||
CoverPath = _GetFullPath(s, s.Cover),
|
||||
AudioPath = _GetFullPath(s, s.Audio),
|
||||
PreviewStart = s.Preview.Source == EDataSource.None ? (float?)null : s.Preview.StartTime,
|
||||
NumPlayed = s.NumPlayed,
|
||||
DateAdded = s.DateAdded
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
private static IList<int> _GetAudioModes(CSong song)
|
||||
{
|
||||
var modes = new List<int>();
|
||||
if (song.HasInstrumental())
|
||||
{
|
||||
modes.Add((int)EAudioMode.TR_AUDIOMODE_NORMAL);
|
||||
modes.Add((int)EAudioMode.TR_AUDIOMODE_INSTRUMENTAL);
|
||||
if (song.HasVocals())
|
||||
{
|
||||
modes.Add((int)EAudioMode.TR_AUDIOMODE_VOCALS);
|
||||
}
|
||||
|
||||
modes.Add((int)EAudioMode.TR_AUDIOMODE_KARAOKE);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
private static string _GetFullPath(CSong song, string file)
|
||||
{
|
||||
if (string.IsNullOrEmpty(file))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Path.GetFullPath(Path.Combine(song.Folder, file));
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region playlists
|
||||
public IList<RemotePlaylist> GetPlaylists()
|
||||
{
|
||||
_CheckReady();
|
||||
return CPlaylists.Playlists.Select(p => new RemotePlaylist
|
||||
{
|
||||
Id = p.Id,
|
||||
Name = p.Name,
|
||||
Entries = p.Songs.Select(s => new RemotePlaylistEntry { SongId = s.SongId, GameMode = (int)s.GameMode, AudioMode = (int)s.AudioMode }).ToList()
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public int CreatePlaylist(string name)
|
||||
{
|
||||
_CheckReady();
|
||||
var id = CPlaylists.NewPlaylist(name);
|
||||
CPlaylists.Save(id);
|
||||
return id;
|
||||
}
|
||||
|
||||
public void RenamePlaylist(int playlistId, string name)
|
||||
{
|
||||
CPlaylists.SetName(playlistId, name);
|
||||
CPlaylists.Save(playlistId);
|
||||
}
|
||||
|
||||
public void DeletePlaylist(int playlistId)
|
||||
{
|
||||
CPlaylists.Delete(playlistId);
|
||||
}
|
||||
|
||||
public void SetPlaylistEntries(int playlistId, IList<RemotePlaylistEntry> entries)
|
||||
{
|
||||
var playlist = CPlaylists.Get(playlistId);
|
||||
if (playlist == null)
|
||||
{
|
||||
throw new KeyNotFoundException("Playlist not found");
|
||||
}
|
||||
|
||||
playlist.Songs = entries.Select(e => new CPlaylistSong(e.SongId, (EGameMode)e.GameMode) { AudioMode = (EAudioMode)e.AudioMode }).ToList();
|
||||
playlist.Save();
|
||||
CWebServer.NotifyPlaylistChanged();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region game
|
||||
public ERemoteStartResult StartSong(RemoteStartRequest request)
|
||||
{
|
||||
if (!CWebQueue.Start(request.SongId, (EGameMode)request.GameMode, (EAudioMode)request.AudioMode, request.PlayerIds, false, out var singsNow))
|
||||
{
|
||||
return ERemoteStartResult.Busy;
|
||||
}
|
||||
|
||||
return singsNow ? ERemoteStartResult.Singing : ERemoteStartResult.PlayerSelection;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region input
|
||||
public void SendKey(ERemoteKey key)
|
||||
{
|
||||
_Keyboard.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, false, false, false, char.MinValue, _ToKeys(key)));
|
||||
}
|
||||
|
||||
public void SendText(string text)
|
||||
{
|
||||
foreach (var chr in text)
|
||||
{
|
||||
_Keyboard.AddKeyEvent(new SKeyEvent(ESender.Keyboard, false, char.IsUpper(chr), false, true, chr, _CharToKeys(chr)));
|
||||
}
|
||||
}
|
||||
|
||||
private static Keys _CharToKeys(char chr)
|
||||
{
|
||||
var upper = char.ToUpperInvariant(chr);
|
||||
if (upper >= 'A' && upper <= 'Z')
|
||||
{
|
||||
return Keys.A + (upper - 'A');
|
||||
}
|
||||
|
||||
if (chr >= '0' && chr <= '9')
|
||||
{
|
||||
return Keys.D0 + (chr - '0');
|
||||
}
|
||||
|
||||
return chr == ' ' ? Keys.Space : Keys.None;
|
||||
}
|
||||
|
||||
private static Keys _ToKeys(ERemoteKey key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case ERemoteKey.Up:
|
||||
return Keys.Up;
|
||||
case ERemoteKey.Down:
|
||||
return Keys.Down;
|
||||
case ERemoteKey.Left:
|
||||
return Keys.Left;
|
||||
case ERemoteKey.Right:
|
||||
return Keys.Right;
|
||||
case ERemoteKey.Enter:
|
||||
return Keys.Return;
|
||||
case ERemoteKey.Escape:
|
||||
return Keys.Escape;
|
||||
case ERemoteKey.Tab:
|
||||
return Keys.Tab;
|
||||
case ERemoteKey.Backspace:
|
||||
return Keys.Back;
|
||||
case ERemoteKey.Space:
|
||||
return Keys.Space;
|
||||
case ERemoteKey.PageUp:
|
||||
return Keys.PageUp;
|
||||
case ERemoteKey.PageDown:
|
||||
return Keys.PageDown;
|
||||
default:
|
||||
return Keys.None;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Log;
|
||||
using VocaluxeLib.Menu;
|
||||
|
||||
namespace Vocaluxe.Base.Web
|
||||
{
|
||||
/// The WebApp queue as the game sees it: a playlist plus requester and singers from the webserver.
|
||||
/// Used by the queue screen and by the webserver to start songs.
|
||||
static class CWebQueue
|
||||
{
|
||||
public sealed class CItem
|
||||
{
|
||||
public int SongId;
|
||||
public EGameMode GameMode;
|
||||
public EAudioMode AudioMode;
|
||||
public string RequestedBy;
|
||||
public IList<Guid> PlayerIds = new List<Guid>();
|
||||
public IList<string> PlayerNames = new List<string>();
|
||||
}
|
||||
|
||||
private static readonly EScreen[] _BusyScreens = { EScreen.Load, EScreen.Sing, EScreen.JukeboxPlayer, EScreen.Party };
|
||||
|
||||
/// Song that was started from the queue; after singing it the game returns to the queue screen.
|
||||
private static int _StartedSongId = -1;
|
||||
|
||||
public static int PlaylistId
|
||||
{
|
||||
get
|
||||
{
|
||||
var name = CWebServer.GetQueuePlaylistName();
|
||||
var playlist = CPlaylists.Playlists.FirstOrDefault(p => p.Name == name);
|
||||
return playlist?.Id ?? -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsQueuePlaylist(int playlistId)
|
||||
{
|
||||
return playlistId >= 0 && playlistId == PlaylistId;
|
||||
}
|
||||
|
||||
/// The entries in queue order. Without running webserver only the playlist is known (no requesters and singers).
|
||||
public static IList<CItem> GetItems()
|
||||
{
|
||||
var items = CWebServer.GetQueueItems();
|
||||
if (items != null)
|
||||
{
|
||||
return items;
|
||||
}
|
||||
|
||||
var playlist = CPlaylists.Get(PlaylistId);
|
||||
if (playlist == null)
|
||||
{
|
||||
return new List<CItem>();
|
||||
}
|
||||
|
||||
return playlist.Songs.Select(s => new CItem { SongId = s.SongId, GameMode = s.GameMode, AudioMode = s.AudioMode }).ToList();
|
||||
}
|
||||
|
||||
public static bool CanStart()
|
||||
{
|
||||
return CParty.CurrentPartyModeId == -1 && !_BusyScreens.Contains(CGraphics.CurrentScreenType);
|
||||
}
|
||||
|
||||
/// Starts singing the song. With singers and configured microphones the player selection is skipped;
|
||||
/// otherwise (or when requested) the player selection is shown with the singers already chosen.
|
||||
public static bool Start(int songId, EGameMode gameMode, EAudioMode audioMode, IList<Guid> playerIds, bool showPlayerSelection, out bool singsNow)
|
||||
{
|
||||
singsNow = false;
|
||||
if (!CanStart() || CSongs.GetSong(songId) == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CParty.SetNormalGameMode();
|
||||
CGame.Reset();
|
||||
CGame.ClearSongs();
|
||||
CGame.AddSong(songId, gameMode, audioMode);
|
||||
if (CGame.GetNumSongs() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var players = (playerIds ?? new List<Guid>()).Where(CProfiles.IsProfileIdValid).Distinct().Take(CSettings.MaxNumPlayer).ToList();
|
||||
if (players.Count > 0)
|
||||
{
|
||||
CConfig.Config.Game.NumPlayers = players.Count;
|
||||
CGame.NumPlayers = players.Count;
|
||||
var isDuet = CGame.GetSong(0).IsDuet;
|
||||
for (var i = 0; i < CSettings.MaxNumPlayer; i++)
|
||||
{
|
||||
CGame.Players[i].ProfileId = i < players.Count ? players[i] : Guid.Empty;
|
||||
CGame.Players[i].VoiceNr = isDuet ? i % 2 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
_StartedSongId = songId;
|
||||
var micsReady = Enumerable.Range(1, players.Count).All(CConfig.IsMicConfig);
|
||||
singsNow = players.Count > 0 && micsReady && !showPlayerSelection;
|
||||
CLog.Information("WebApp queue: starting song {SongId} with {Players} of {Chosen} chosen singers, microphones ready: {MicsReady}, player selection: {Selection}",
|
||||
new object[] { songId, players.Count, playerIds?.Count ?? 0, micsReady, !singsNow });
|
||||
if (!singsNow)
|
||||
{
|
||||
CBackgroundMusic.LoadPreview(CSongs.GetSong(songId));
|
||||
}
|
||||
|
||||
CGraphics.FadeTo(singsNow ? EScreen.Sing : EScreen.Names);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Called when leaving the score screens: goes back to the queue screen if the song was started from the queue.
|
||||
public static bool ReturnAfterSinging()
|
||||
{
|
||||
var startedFromQueue = _StartedSongId >= 0 && CParty.CurrentPartyModeId == -1 && CGame.GetSong(0)?.Id == _StartedSongId;
|
||||
_StartedSongId = -1;
|
||||
if (!startedFromQueue)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CGraphics.FadeTo(EScreen.WebQueue);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SetModes(int index, EGameMode gameMode, EAudioMode audioMode)
|
||||
{
|
||||
var playlist = CPlaylists.Get(PlaylistId);
|
||||
if (playlist == null || index < 0 || index >= playlist.Songs.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
playlist.Songs[index].GameMode = gameMode;
|
||||
playlist.Songs[index].AudioMode = audioMode;
|
||||
playlist.Save();
|
||||
CWebServer.NotifyPlaylistChanged();
|
||||
}
|
||||
|
||||
public static void Remove(int index)
|
||||
{
|
||||
var playlist = CPlaylists.Get(PlaylistId);
|
||||
if (playlist == null || index < 0 || index >= playlist.Songs.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
playlist.DeleteSong(index);
|
||||
playlist.Save();
|
||||
CWebServer.NotifyPlaylistChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Log;
|
||||
#if WIN
|
||||
using Newtonsoft.Json.Linq;
|
||||
#endif
|
||||
#if WIN
|
||||
using VocaluxeWeb.Hosting;
|
||||
#endif
|
||||
|
||||
namespace Vocaluxe.Base.Web
|
||||
{
|
||||
/// Starts and stops the embedded webserver (project VocaluxeWeb) and runs its requests on the main thread.
|
||||
/// The webserver is not available in Linux builds yet.
|
||||
static class CWebServer
|
||||
{
|
||||
private const string _CertificateFileName = "WebServer.pfx";
|
||||
private const string _SettingsFileName = "WebServer.json";
|
||||
private const string _CacheFolderName = "WebCache";
|
||||
private const string _DefaultQueuePlaylistName = "WebApp Queue";
|
||||
|
||||
public static readonly CRemoteKeyboard Controller = new CRemoteKeyboard();
|
||||
|
||||
#if WIN
|
||||
private static CWebHost _Host;
|
||||
#endif
|
||||
private static readonly List<string> _PhotosOfThisRound = new List<string>();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
if (CConfig.Config.Server.ServerActive != EOffOn.TR_CONFIG_ON)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if WIN
|
||||
var options = new CWebServerOptions
|
||||
{
|
||||
Port = CConfig.Config.Server.ServerPort,
|
||||
UseHttps = CConfig.Config.Server.ServerEncryption == EOffOn.TR_CONFIG_ON,
|
||||
WebRoot = Path.Combine(CSettings.ProgramFolder, CSettings.FolderNameWebsite),
|
||||
CertificatePath = Path.Combine(CSettings.DataFolder, _CertificateFileName),
|
||||
SettingsPath = Path.Combine(CSettings.DataFolder, _SettingsFileName),
|
||||
CachePath = Path.Combine(CSettings.DataFolder, _CacheFolderName),
|
||||
OnError = e => CLog.Error(e, "Webserver request failed")
|
||||
};
|
||||
|
||||
var host = new CWebHost(new CVocaluxeRemote(Controller), options);
|
||||
try
|
||||
{
|
||||
host.Start();
|
||||
_Host = host;
|
||||
CLog.Information("Webserver running at {Address}", new object[] { host.Address });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
host.Dispose();
|
||||
CLog.Error(e, "Could not start the webserver on port {Port}. You may try a different port (change it in config.xml).", new object[] { options.Port }, true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void Close()
|
||||
{
|
||||
#if WIN
|
||||
_Host?.Dispose();
|
||||
_Host = null;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Runs pending webserver requests. Called once per frame from the main thread.
|
||||
public static void ProcessTasks()
|
||||
{
|
||||
#if WIN
|
||||
_Host?.Tick();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static bool IsServerRunning()
|
||||
{
|
||||
#if WIN
|
||||
return _Host != null && _Host.IsRunning;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static string GetServerAddress()
|
||||
{
|
||||
#if WIN
|
||||
return _Host?.Address?.AbsoluteUri ?? "";
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Name of the playlist used as WebApp queue; read from the webserver settings also while the server is off.
|
||||
public static string GetQueuePlaylistName()
|
||||
{
|
||||
#if WIN
|
||||
if (_Host != null)
|
||||
{
|
||||
return _Host.QueuePlaylistName;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var path = Path.Combine(CSettings.DataFolder, _SettingsFileName);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var name = (string)JObject.Parse(File.ReadAllText(path))["QueuePlaylistName"];
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.Warning(e, "Could not read the webserver settings");
|
||||
}
|
||||
#endif
|
||||
return _DefaultQueuePlaylistName;
|
||||
}
|
||||
|
||||
/// The queue with requesters and singers, or null if the webserver is not running.
|
||||
public static IList<CWebQueue.CItem> GetQueueItems()
|
||||
{
|
||||
#if WIN
|
||||
return _Host?.GetQueueForGame().Select(i => new CWebQueue.CItem
|
||||
{
|
||||
SongId = i.SongId,
|
||||
GameMode = (EGameMode)i.GameMode,
|
||||
AudioMode = (EAudioMode)i.AudioMode,
|
||||
RequestedBy = i.RequestedBy,
|
||||
PlayerIds = i.PlayerIds,
|
||||
PlayerNames = i.PlayerNames
|
||||
}).ToList();
|
||||
#else
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// The queue entry at this position was started from the queue screen: it leaves the queue.
|
||||
public static void MarkQueueEntryStarted(int index)
|
||||
{
|
||||
#if WIN
|
||||
if (_Host != null)
|
||||
{
|
||||
_Host.MarkQueueEntryStarted(index);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
CWebQueue.Remove(index);
|
||||
}
|
||||
|
||||
/// Increases whenever a playlist was changed by the webserver or the queue screen, so open views can reload it.
|
||||
public static int PlaylistVersion { get; private set; }
|
||||
|
||||
public static void NotifyPlaylistChanged()
|
||||
{
|
||||
PlaylistVersion++;
|
||||
}
|
||||
|
||||
/// Photos taken with the WebApp since the last call (shown as slideshow on the score screen).
|
||||
public static string[] GetPhotosOfThisRound()
|
||||
{
|
||||
lock (_PhotosOfThisRound)
|
||||
{
|
||||
var result = _PhotosOfThisRound.ToArray();
|
||||
_PhotosOfThisRound.Clear();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Server;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
|
||||
@@ -451,7 +451,7 @@ namespace Vocaluxe.Lib.Draw
|
||||
while (_Run)
|
||||
{
|
||||
_CheckQueue();
|
||||
CVocaluxeServer.ProcessServerTasks();
|
||||
CWebServer.ProcessTasks();
|
||||
|
||||
//We want to begin drawing
|
||||
_OnBeforeDraw();
|
||||
|
||||
@@ -27,7 +27,7 @@ using System.Windows.Forms;
|
||||
using SQLitePCL;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Fonts;
|
||||
using Vocaluxe.Base.Server;
|
||||
using Vocaluxe.Base.Web;
|
||||
using Vocaluxe.Base.ThemeSystem;
|
||||
using Vocaluxe.Reporting;
|
||||
using VocaluxeLib.Log;
|
||||
@@ -284,7 +284,7 @@ namespace Vocaluxe
|
||||
// Init Server
|
||||
using (CBenchmark.Time("Init Server"))
|
||||
{
|
||||
CVocaluxeServer.Init();
|
||||
CWebServer.Init();
|
||||
}
|
||||
|
||||
Application.DoEvents();
|
||||
@@ -360,11 +360,11 @@ namespace Vocaluxe
|
||||
|
||||
try
|
||||
{
|
||||
CVocaluxeServer.Close();
|
||||
CWebServer.Close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CLog.Error(e, "Error during shutdown! (CVocaluxeServer)");
|
||||
CLog.Error(e, "Error during shutdown! (CWebServer)");
|
||||
}
|
||||
|
||||
try
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
using System.Windows.Forms;
|
||||
using QRCoder;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Server;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
@@ -34,6 +34,7 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
|
||||
private CTextureRef _QRServerAddress;
|
||||
private string _QRAddress;
|
||||
private const string _StaticQRServer = "StaticQRServer";
|
||||
|
||||
private const string _TextServerAddress = "TextServerAddress";
|
||||
@@ -50,16 +51,16 @@ namespace Vocaluxe.Screens
|
||||
public override void OnShow()
|
||||
{
|
||||
base.OnShow();
|
||||
if (_QRServerAddress == null)
|
||||
if (_QRServerAddress == null || _QRAddress != CWebServer.GetServerAddress())
|
||||
{
|
||||
_GenerateQRs();
|
||||
_Statics[_StaticQRServer].Texture = _QRServerAddress;
|
||||
_Texts[_TextServerAddress].Text = CVocaluxeServer.GetServerAddress();
|
||||
_Texts[_TextServerAddress].Text = CWebServer.GetServerAddress();
|
||||
}
|
||||
|
||||
_Texts[_TextServerAddress].Visible = CVocaluxeServer.IsServerRunning();
|
||||
_Statics[_StaticQRServer].Visible = CVocaluxeServer.IsServerRunning();
|
||||
_Texts[_TextServerNotRunning].Visible = !CVocaluxeServer.IsServerRunning();
|
||||
_Texts[_TextServerAddress].Visible = CWebServer.IsServerRunning();
|
||||
_Statics[_StaticQRServer].Visible = CWebServer.IsServerRunning();
|
||||
_Texts[_TextServerNotRunning].Visible = !CWebServer.IsServerRunning();
|
||||
}
|
||||
|
||||
public override bool HandleMouse(SMouseEvent mouseEvent)
|
||||
@@ -96,7 +97,9 @@ namespace Vocaluxe.Screens
|
||||
var qr = new QRCodeGenerator();
|
||||
|
||||
//ServerAddress
|
||||
var qrcode = qr.CreateQrCode(CVocaluxeServer.GetServerAddress(), QRCodeGenerator.ECCLevel.H);
|
||||
CDraw.RemoveTexture(ref _QRServerAddress);
|
||||
_QRAddress = CWebServer.GetServerAddress();
|
||||
var qrcode = qr.CreateQrCode(_QRAddress, QRCodeGenerator.ECCLevel.H);
|
||||
_QRServerAddress = CDraw.AddTexture(qrcode.GetGraphic(20));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
@@ -510,7 +511,7 @@ namespace Vocaluxe.Screens
|
||||
_HighscoreStream = -1;
|
||||
}
|
||||
|
||||
if (!CJukebox.ReturnAfterSinging())
|
||||
if (!CJukebox.ReturnAfterSinging() && !CWebQueue.ReturnAfterSinging())
|
||||
{
|
||||
CParty.LeavingHighscore();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Draw;
|
||||
using VocaluxeLib.Menu;
|
||||
@@ -954,7 +955,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private static void _FadeBack()
|
||||
{
|
||||
if (!CJukebox.ReturnAfterSinging())
|
||||
if (!CJukebox.ReturnAfterSinging() && !CWebQueue.ReturnAfterSinging())
|
||||
{
|
||||
CGraphics.FadeTo(EScreen.Song);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Server;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Game;
|
||||
using VocaluxeLib.Menu;
|
||||
@@ -205,6 +205,12 @@ namespace Vocaluxe.Screens
|
||||
_SetVisibility();
|
||||
_UpdateRatings();
|
||||
_SlideShowBG.Visible = _UpdateBackground();
|
||||
|
||||
var lastSong = CGame.GetSong(CGame.NumRounds - 1);
|
||||
if (lastSong != null)
|
||||
{
|
||||
CBackgroundMusic.LoadPreview(lastSong);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnClose()
|
||||
@@ -749,7 +755,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private bool _UpdateBackground()
|
||||
{
|
||||
var photos = CVocaluxeServer.GetPhotosOfThisRound();
|
||||
var photos = CWebServer.GetPhotosOfThisRound();
|
||||
_SlideShowBG.RemoveSlideShowTextures();
|
||||
foreach (var photo in photos)
|
||||
{
|
||||
@@ -765,7 +771,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
if (_IsKaraokeMode(-1))
|
||||
{
|
||||
if (!CJukebox.ReturnAfterSinging())
|
||||
if (!CJukebox.ReturnAfterSinging() && !CWebQueue.ReturnAfterSinging())
|
||||
{
|
||||
CGraphics.FadeTo(EScreen.Song);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ using System.Linq;
|
||||
using System.Timers;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Menu;
|
||||
using VocaluxeLib.Menu.SongMenu;
|
||||
@@ -42,7 +43,7 @@ namespace Vocaluxe.Screens
|
||||
// Version number for theme files. Increment it, if you've changed something on the theme files!
|
||||
protected override int _ScreenVersion
|
||||
{
|
||||
get { return 16; }
|
||||
get { return 17; }
|
||||
}
|
||||
|
||||
private const string _TextCategory = "TextCategory";
|
||||
@@ -86,6 +87,7 @@ namespace Vocaluxe.Screens
|
||||
private const string _ButtonOptionsSingAllVisible = "ButtonOptionsSingAllVisible";
|
||||
private const string _ButtonOptionsOpenSelectedItem = "ButtonOptionsOpenSelectedItem";
|
||||
private const string _ButtonOptionsRandomMedley = "ButtonOptionsRandomMedley";
|
||||
private const string _ButtonOptionsWebQueue = "ButtonOptionsWebQueue";
|
||||
private const string _ButtonOptionsStartMedley = "ButtonOptionsStartMedley";
|
||||
private const string _ButtonStart = "ButtonStart";
|
||||
private const string _ButtonOptionsHighscore = "ButtonOptionsHighscore";
|
||||
@@ -161,6 +163,7 @@ namespace Vocaluxe.Screens
|
||||
|
||||
private ISongMenu _SongMenu;
|
||||
private CPlaylist _Playlist;
|
||||
private int _PlaylistVersion;
|
||||
|
||||
private System.Timers.Timer _TimerShortInfoText;
|
||||
|
||||
@@ -235,6 +238,7 @@ namespace Vocaluxe.Screens
|
||||
blist.Add(_ButtonOpenOptions);
|
||||
blist.Add(_ButtonStart);
|
||||
blist.Add(_ButtonOptionsRandomMedley);
|
||||
blist.Add(_ButtonOptionsWebQueue);
|
||||
blist.Add(_ButtonOptionsStartMedley);
|
||||
blist.Add(_ButtonOptionsHighscore);
|
||||
|
||||
@@ -658,6 +662,11 @@ namespace Vocaluxe.Screens
|
||||
{
|
||||
_ToggleSongOptions(ESongOptionsView.Medley);
|
||||
}
|
||||
else if (_Buttons[_ButtonOptionsWebQueue].Selected)
|
||||
{
|
||||
_ToggleSongOptions(ESongOptionsView.None);
|
||||
CGraphics.FadeTo(EScreen.WebQueue);
|
||||
}
|
||||
else if (_Buttons[_ButtonOptionsStartMedley].Selected)
|
||||
{
|
||||
_ToggleSongOptions(ESongOptionsView.None);
|
||||
@@ -878,6 +887,12 @@ namespace Vocaluxe.Screens
|
||||
_ToggleSongOptions(ESongOptionsView.Medley);
|
||||
return true;
|
||||
}
|
||||
else if (_Buttons[_ButtonOptionsWebQueue].Selected)
|
||||
{
|
||||
_ToggleSongOptions(ESongOptionsView.None);
|
||||
CGraphics.FadeTo(EScreen.WebQueue);
|
||||
return true;
|
||||
}
|
||||
else if (_Buttons[_ButtonOptionsStartMedley].Selected)
|
||||
{
|
||||
_ToggleSongOptions(ESongOptionsView.None);
|
||||
@@ -1053,6 +1068,15 @@ namespace Vocaluxe.Screens
|
||||
CSongs.OnCategoryChanged += _OnCategoryChanged;
|
||||
}
|
||||
|
||||
private void _UpdatePlaylistIfChanged()
|
||||
{
|
||||
if (_PlaylistVersion != CWebServer.PlaylistVersion)
|
||||
{
|
||||
_PlaylistVersion = CWebServer.PlaylistVersion;
|
||||
_Playlist.UpdatePlaylist();
|
||||
}
|
||||
}
|
||||
|
||||
private static void _OnCategoryChanged()
|
||||
{
|
||||
CSound.SetGlobalVolume(CSongs.IsInCategory ? CConfig.PreviewMusicVolume : CConfig.BackgroundMusicVolume);
|
||||
@@ -1068,6 +1092,7 @@ namespace Vocaluxe.Screens
|
||||
}
|
||||
else
|
||||
{
|
||||
_UpdatePlaylistIfChanged();
|
||||
_Playlist.UpdateGame();
|
||||
}
|
||||
}
|
||||
@@ -1867,6 +1892,7 @@ namespace Vocaluxe.Screens
|
||||
_Buttons[_ButtonOptionsSingAllVisible].Visible = false;
|
||||
_Buttons[_ButtonOptionsOpenSelectedItem].Visible = false;
|
||||
_Buttons[_ButtonOptionsRandomMedley].Visible = false;
|
||||
_Buttons[_ButtonOptionsWebQueue].Visible = false;
|
||||
_Buttons[_ButtonOptionsStartMedley].Visible = false;
|
||||
_Buttons[_ButtonOptionsHighscore].Visible = false;
|
||||
_Texts[_TextOptionsTitle].Visible = false;
|
||||
@@ -1956,7 +1982,7 @@ namespace Vocaluxe.Screens
|
||||
},
|
||||
new[] { _TextOptionsPlayerSelect, _TextOptionsPlaylist },
|
||||
new[] { _SelectSlideOptionsPlayerSelect, _SelectSlideOptionsPlaylistAdd },
|
||||
new[] { _ButtonOptionsPlaylist, _ButtonOptionsHighscore, _ButtonOptionsClose });
|
||||
new[] { _ButtonOptionsPlaylist, _ButtonOptionsWebQueue, _ButtonOptionsHighscore, _ButtonOptionsClose });
|
||||
}
|
||||
|
||||
private void _SetGeneralOptionsOffsetY(float singAllOffset, float medleyOffset)
|
||||
@@ -2060,6 +2086,7 @@ namespace Vocaluxe.Screens
|
||||
_SelectSlides[_SelectSlideOptionsPlaylistAdd].Visible = true;
|
||||
_Buttons[_ButtonOptionsSing].Visible = true;
|
||||
_Buttons[_ButtonOptionsPlaylist].Visible = true;
|
||||
_Buttons[_ButtonOptionsWebQueue].Visible = !_Sso.Selection.PartyMode;
|
||||
_Buttons[_ButtonOptionsHighscore].Visible = true;
|
||||
|
||||
_Texts[_TextOptionsTitle].Visible = false;
|
||||
|
||||
@@ -0,0 +1,418 @@
|
||||
#region license
|
||||
// This file is part of Vocaluxe.
|
||||
//
|
||||
// Vocaluxe 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Vocaluxe 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 Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Base.Web;
|
||||
using VocaluxeLib;
|
||||
using VocaluxeLib.Menu;
|
||||
|
||||
namespace Vocaluxe.Screens
|
||||
{
|
||||
/// The WebApp queue: songs added with the WebApp, shown with the next song, requester and singers.
|
||||
/// Only the next song can be started (the order is managed in the WebApp); its game mode, audio mode and singers can still be changed.
|
||||
/// Opened from the general options of the song screen.
|
||||
public class CScreenWebQueue : CMenu
|
||||
{
|
||||
protected override int _ScreenVersion
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
|
||||
private const int _NumRows = 8;
|
||||
private const long _RefreshIntervalMs = 500;
|
||||
|
||||
private const string _TextInfo = "TextInfo";
|
||||
private const string _TextWarning = "TextWarning";
|
||||
private const string _TextNextLabel = "TextNextLabel";
|
||||
private const string _TextNextSong = "TextNextSong";
|
||||
private const string _TextNextDetails = "TextNextDetails";
|
||||
private const string _TextNextPlayers = "TextNextPlayers";
|
||||
private const string _TextEmpty = "TextEmpty";
|
||||
private const string _TextEmpty2 = "TextEmpty2";
|
||||
private const string _TextMore = "TextMore";
|
||||
private const string _TextMode = "TextMode";
|
||||
private const string _TextAudio = "TextAudio";
|
||||
|
||||
private const string _StaticWarning = "StaticWarning";
|
||||
private const string _StaticNextCover = "StaticNextCover";
|
||||
private const string _StaticNextPanel = "StaticNextPanel";
|
||||
|
||||
private const string _SelectSlideMode = "SelectSlideMode";
|
||||
private const string _SelectSlideAudio = "SelectSlideAudio";
|
||||
|
||||
private const string _ButtonBack = "ButtonBack";
|
||||
private const string _ButtonServer = "ButtonServer";
|
||||
private const string _ButtonPlayers = "ButtonPlayers";
|
||||
private const string _ButtonStart = "ButtonStart";
|
||||
private const string _ButtonEntryPrefix = "ButtonEntry";
|
||||
|
||||
private readonly Stopwatch _RefreshTimer = new Stopwatch();
|
||||
private IList<CWebQueue.CItem> _Items = new List<CWebQueue.CItem>();
|
||||
private int _Offset;
|
||||
private string _SlidesFor = "";
|
||||
private int _PlaylistVersion = -1;
|
||||
private int _WarningStream = -1;
|
||||
private bool _HasPlayedWarningSound;
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
_ThemeTexts = new string[]
|
||||
{
|
||||
_TextInfo, _TextWarning, _TextNextLabel, _TextNextSong, _TextNextDetails, _TextNextPlayers, _TextEmpty, _TextEmpty2, _TextMore, _TextMode, _TextAudio
|
||||
};
|
||||
_ThemeStatics = new string[] { _StaticWarning, _StaticNextCover, _StaticNextPanel };
|
||||
_ThemeSelectSlides = new string[] { _SelectSlideMode, _SelectSlideAudio };
|
||||
_ThemeButtons = new[] { _ButtonBack, _ButtonServer, _ButtonPlayers, _ButtonStart }
|
||||
.Concat(Enumerable.Range(1, _NumRows).Select(i => _ButtonEntryPrefix + i)).ToArray();
|
||||
}
|
||||
|
||||
public override void LoadTheme(string xmlPath)
|
||||
{
|
||||
base.LoadTheme(xmlPath);
|
||||
|
||||
//The list only shows the order, the entries can't be selected
|
||||
for (var row = 1; row <= _NumRows; row++)
|
||||
{
|
||||
_Buttons[_ButtonEntryPrefix + row].Selectable = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnShow()
|
||||
{
|
||||
base.OnShow();
|
||||
_HasPlayedWarningSound = false;
|
||||
_Offset = 0;
|
||||
_SlidesFor = "";
|
||||
_Refresh();
|
||||
_SelectElement(_Items.Count > 0 ? _Buttons[_ButtonStart] : _Buttons[_ButtonBack]);
|
||||
_RefreshTimer.Restart();
|
||||
}
|
||||
|
||||
public override void OnClose()
|
||||
{
|
||||
base.OnClose();
|
||||
if (_WarningStream != -1)
|
||||
{
|
||||
CSound.Close(_WarningStream);
|
||||
_WarningStream = -1;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandleInput(SKeyEvent keyEvent)
|
||||
{
|
||||
base.HandleInput(keyEvent);
|
||||
|
||||
if (keyEvent.KeyPressed)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (keyEvent.Key)
|
||||
{
|
||||
case Keys.Escape:
|
||||
case Keys.Back:
|
||||
CGraphics.FadeTo(EScreen.Song);
|
||||
break;
|
||||
|
||||
case Keys.Enter:
|
||||
_HandleEnter();
|
||||
break;
|
||||
|
||||
case Keys.PageDown:
|
||||
_Scroll(_NumRows);
|
||||
break;
|
||||
|
||||
case Keys.PageUp:
|
||||
_Scroll(-_NumRows);
|
||||
break;
|
||||
|
||||
case Keys.Left:
|
||||
case Keys.Right:
|
||||
_ReadModes();
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool HandleMouse(SMouseEvent mouseEvent)
|
||||
{
|
||||
base.HandleMouse(mouseEvent);
|
||||
|
||||
if (mouseEvent.Wheel != 0)
|
||||
{
|
||||
_Scroll(Math.Sign(mouseEvent.Wheel));
|
||||
}
|
||||
|
||||
if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent))
|
||||
{
|
||||
if (_SelectSlides[_SelectSlideMode].Selected || _SelectSlides[_SelectSlideAudio].Selected)
|
||||
{
|
||||
_ReadModes();
|
||||
}
|
||||
else
|
||||
{
|
||||
_HandleEnter();
|
||||
}
|
||||
}
|
||||
else if (mouseEvent.RB)
|
||||
{
|
||||
CGraphics.FadeTo(EScreen.Song);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool UpdateGame()
|
||||
{
|
||||
if (_PlaylistVersion != CWebServer.PlaylistVersion || _RefreshTimer.ElapsedMilliseconds > _RefreshIntervalMs)
|
||||
{
|
||||
_Refresh();
|
||||
_RefreshTimer.Restart();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void _HandleEnter()
|
||||
{
|
||||
if (_Buttons[_ButtonBack].Selected)
|
||||
{
|
||||
CGraphics.FadeTo(EScreen.Song);
|
||||
}
|
||||
else if (_Buttons[_ButtonServer].Selected)
|
||||
{
|
||||
CGraphics.ShowPopup(EPopupScreens.PopupServerQR);
|
||||
}
|
||||
else if (_Buttons[_ButtonStart].Selected)
|
||||
{
|
||||
_Start(false);
|
||||
}
|
||||
else if (_Buttons[_ButtonPlayers].Selected)
|
||||
{
|
||||
_Start(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the next song. Directly singing removes it from the queue right away;
|
||||
/// with the player selection it stays until singing really starts (the selection can be cancelled).
|
||||
private void _Start(bool showPlayerSelection)
|
||||
{
|
||||
if (_Items.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var item = _Items[0];
|
||||
if (CWebQueue.Start(item.SongId, item.GameMode, item.AudioMode, item.PlayerIds, showPlayerSelection, out var singsNow) && singsNow)
|
||||
{
|
||||
CWebServer.MarkQueueEntryStarted(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void _Scroll(int rows)
|
||||
{
|
||||
var offset = Math.Max(0, Math.Min(_Items.Count - 1 - _NumRows, _Offset + rows));
|
||||
if (offset != _Offset)
|
||||
{
|
||||
_Offset = offset;
|
||||
_Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void _ReadModes()
|
||||
{
|
||||
if (_Items.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var item = _Items[0];
|
||||
var gameMode = _SelectSlides[_SelectSlideMode].Visible ? (EGameMode)_SelectSlides[_SelectSlideMode].SelectedTag : item.GameMode;
|
||||
var audioMode = _SelectSlides[_SelectSlideAudio].Visible ? (EAudioMode)_SelectSlides[_SelectSlideAudio].SelectedTag : item.AudioMode;
|
||||
if (gameMode != item.GameMode || audioMode != item.AudioMode)
|
||||
{
|
||||
CWebQueue.SetModes(0, gameMode, audioMode);
|
||||
_Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void _Refresh()
|
||||
{
|
||||
_PlaylistVersion = CWebServer.PlaylistVersion;
|
||||
_Items = CWebQueue.GetItems();
|
||||
_Offset = Math.Max(0, Math.Min(_Offset, _Items.Count - 1 - _NumRows));
|
||||
|
||||
var serverRunning = CWebServer.IsServerRunning();
|
||||
_Statics[_StaticWarning].Visible = !serverRunning;
|
||||
_Texts[_TextWarning].Visible = !serverRunning;
|
||||
_Texts[_TextInfo].Visible = serverRunning;
|
||||
if (!serverRunning && !_HasPlayedWarningSound)
|
||||
{
|
||||
_WarningStream = CSound.PlaySound(ESounds.Warning, false);
|
||||
CSound.SetStreamVolume(_WarningStream, CConfig.SoundEffectVolume);
|
||||
_HasPlayedWarningSound = true;
|
||||
}
|
||||
|
||||
_UpdateNext();
|
||||
_UpdateRows();
|
||||
_UpdateSlides();
|
||||
|
||||
var hasItems = _Items.Count > 0;
|
||||
_Texts[_TextEmpty].Visible = !hasItems;
|
||||
_Texts[_TextEmpty2].Visible = !hasItems;
|
||||
_Buttons[_ButtonStart].Visible = hasItems;
|
||||
_Buttons[_ButtonPlayers].Visible = hasItems;
|
||||
if (!hasItems && (_Buttons[_ButtonStart].Selected || _Buttons[_ButtonPlayers].Selected || _SelectSlides[_SelectSlideMode].Selected ||
|
||||
_SelectSlides[_SelectSlideAudio].Selected))
|
||||
{
|
||||
_SelectElement(_Buttons[_ButtonBack]);
|
||||
}
|
||||
}
|
||||
|
||||
private void _UpdateNext()
|
||||
{
|
||||
var visible = _Items.Count > 0;
|
||||
foreach (var text in new[] { _TextNextLabel, _TextNextSong, _TextNextDetails, _TextNextPlayers })
|
||||
{
|
||||
_Texts[text].Visible = visible;
|
||||
}
|
||||
|
||||
_Statics[_StaticNextCover].Visible = visible;
|
||||
_Statics[_StaticNextPanel].Visible = visible;
|
||||
if (!visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var item = _Items[0];
|
||||
var song = CSongs.GetSong(item.SongId);
|
||||
_Statics[_StaticNextCover].Texture = song?.CoverTextureBig ?? CCover.NoCover;
|
||||
_Texts[_TextNextSong].Text = song == null ? "?" : song.Artist + " - " + song.Title;
|
||||
_Texts[_TextNextDetails].Text = _GetDetails(item);
|
||||
_Texts[_TextNextPlayers].Text = _GetPlayers(item);
|
||||
}
|
||||
|
||||
/// The songs after the next one.
|
||||
private void _UpdateRows()
|
||||
{
|
||||
for (var row = 1; row <= _NumRows; row++)
|
||||
{
|
||||
var index = 1 + _Offset + row - 1;
|
||||
var button = _Buttons[_ButtonEntryPrefix + row];
|
||||
button.Visible = index < _Items.Count;
|
||||
if (!button.Visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var item = _Items[index];
|
||||
var song = CSongs.GetSong(item.SongId);
|
||||
var title = song == null ? "?" : song.Artist + " - " + song.Title;
|
||||
var requester = string.IsNullOrEmpty(item.RequestedBy) ? "" : " (" + item.RequestedBy + ")";
|
||||
button.Text.Text = (index + 1) + ". " + title + requester;
|
||||
}
|
||||
|
||||
var more = _Items.Count - 1 - _Offset - _NumRows;
|
||||
_Texts[_TextMore].Visible = more > 0;
|
||||
_Texts[_TextMore].Text = CLanguage.Translate("TR_SCREENWEBQUEUE_MORE").Replace("%d", more.ToString());
|
||||
}
|
||||
|
||||
/// Game mode and audio mode of the next song; only modes the song supports.
|
||||
private void _UpdateSlides()
|
||||
{
|
||||
var item = _Items.Count > 0 ? _Items[0] : null;
|
||||
var song = item == null ? null : CSongs.GetSong(item.SongId);
|
||||
var key = song == null ? null : item.SongId + ":" + item.GameMode + ":" + item.AudioMode;
|
||||
if (key == _SlidesFor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_SlidesFor = key;
|
||||
var modes = song?.AvailableGameModes ?? new List<EGameMode>();
|
||||
_SelectSlides[_SelectSlideMode].Clear();
|
||||
foreach (var mode in modes)
|
||||
{
|
||||
_SelectSlides[_SelectSlideMode].AddValue(mode.ToString(), null, (int)mode);
|
||||
}
|
||||
|
||||
_SelectSlides[_SelectSlideMode].Visible = modes.Count > 1;
|
||||
_Texts[_TextMode].Visible = modes.Count > 1;
|
||||
if (item != null && modes.Contains(item.GameMode))
|
||||
{
|
||||
_SelectSlides[_SelectSlideMode].SelectedTag = (int)item.GameMode;
|
||||
}
|
||||
|
||||
var audioModes = new List<EAudioMode>();
|
||||
if (song != null && song.HasInstrumental())
|
||||
{
|
||||
audioModes.Add(EAudioMode.TR_AUDIOMODE_NORMAL);
|
||||
audioModes.Add(EAudioMode.TR_AUDIOMODE_INSTRUMENTAL);
|
||||
if (song.HasVocals())
|
||||
{
|
||||
audioModes.Add(EAudioMode.TR_AUDIOMODE_VOCALS);
|
||||
}
|
||||
|
||||
audioModes.Add(EAudioMode.TR_AUDIOMODE_KARAOKE);
|
||||
}
|
||||
|
||||
_SelectSlides[_SelectSlideAudio].Clear();
|
||||
foreach (var mode in audioModes)
|
||||
{
|
||||
_SelectSlides[_SelectSlideAudio].AddValue(mode.ToString(), null, (int)mode);
|
||||
}
|
||||
|
||||
_SelectSlides[_SelectSlideAudio].Visible = audioModes.Count > 1;
|
||||
_Texts[_TextAudio].Visible = audioModes.Count > 1;
|
||||
if (item != null && audioModes.Contains(item.AudioMode))
|
||||
{
|
||||
_SelectSlides[_SelectSlideAudio].SelectedTag = (int)item.AudioMode;
|
||||
}
|
||||
}
|
||||
|
||||
private static string _GetDetails(CWebQueue.CItem item)
|
||||
{
|
||||
var parts = new List<string> { CLanguage.Translate(item.GameMode.ToString()) };
|
||||
if (item.AudioMode != EAudioMode.TR_AUDIOMODE_NORMAL)
|
||||
{
|
||||
parts.Add(CLanguage.Translate(item.AudioMode.ToString()));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.RequestedBy))
|
||||
{
|
||||
parts.Add(CLanguage.Translate("TR_SCREENWEBQUEUE_ADDEDBY").Replace("%s", item.RequestedBy));
|
||||
}
|
||||
|
||||
return string.Join(" · ", parts);
|
||||
}
|
||||
|
||||
private static string _GetPlayers(CWebQueue.CItem item)
|
||||
{
|
||||
return item.PlayerNames.Count > 0
|
||||
? CLanguage.Translate("TR_SCREENWEBQUEUE_SINGERS").Replace("%s", string.Join(", ", item.PlayerNames))
|
||||
: CLanguage.Translate("TR_SCREENWEBQUEUE_NOSINGERS");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,8 +178,6 @@
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.ServiceModel.Web" />
|
||||
<Reference Include="System.Transactions" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.XML" />
|
||||
@@ -208,13 +206,6 @@
|
||||
<Compile Include="Base\CCoverGenerator.cs" />
|
||||
<Compile Include="Base\CPlaylistElement.cs" />
|
||||
<Compile Include="Base\CRecord.cs" />
|
||||
<Compile Include="Base\Server\CWebservice.cs" />
|
||||
<Compile Include="Base\Server\ICWebservice.cs" />
|
||||
<Compile Include="Base\Server\Session.cs" />
|
||||
<Compile Include="Base\Server\SessionControl.cs" />
|
||||
<Compile Include="Base\Server\UserRights.cs" />
|
||||
<Compile Include="Base\Server\UserRoleControl.cs" />
|
||||
<Compile Include="Base\Server\UserRoles.cs" />
|
||||
<Compile Include="Base\ThemeSystem\CBaseTheme.cs" />
|
||||
<Compile Include="Base\ThemeSystem\CPartySkin.cs" />
|
||||
<Compile Include="Base\ThemeSystem\CBaseSkin.cs" />
|
||||
@@ -272,8 +263,6 @@
|
||||
<Compile Include="Base\CWebcam.cs" />
|
||||
<Compile Include="Base\Fonts\CFonts.cs" />
|
||||
<Compile Include="Base\Fonts\CGlyph.cs" />
|
||||
<Compile Include="Base\Server\CVocaluxeServer.cs" />
|
||||
<Compile Include="Base\Server\VocaluxeStructs.cs" />
|
||||
<Compile Include="CProgrammHelper.cs" />
|
||||
<Compile Include="CSplashScreen.cs">
|
||||
<SubType>Form</SubType>
|
||||
@@ -350,6 +339,7 @@
|
||||
<Compile Include="Screens\CScreenStatisticsDetail.cs" />
|
||||
<Compile Include="Screens\CScreenJukebox.cs" />
|
||||
<Compile Include="Screens\CScreenJukeboxPlayer.cs" />
|
||||
<Compile Include="Screens\CScreenWebQueue.cs" />
|
||||
<Compile Include="Screens\CScreenProfiles.cs" />
|
||||
<Compile Include="Screens\CScreenScore.cs" />
|
||||
<Compile Include="Screens\CScreenSing.cs" />
|
||||
@@ -361,151 +351,19 @@
|
||||
<Compile Include="Screens\CScreenOptionsTheme.cs" />
|
||||
<Compile Include="Screens\CScreenOptionsGraphics.cs" />
|
||||
<Compile Include="Screens\CScreenOptionsServer.cs" />
|
||||
<Compile Include="Base\Web\CWebServer.cs" />
|
||||
<Compile Include="Base\Web\CRemoteKeyboard.cs" />
|
||||
<Compile Include="Base\Web\CWebQueue.cs" />
|
||||
<Compile Include="Base\Web\CVocaluxeRemote.cs" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'" />
|
||||
<Compile Include="Screens\CScreenOptionsSongFolders.cs" />
|
||||
<None Include="app.config">
|
||||
<SubType>Designer</SubType>
|
||||
</None>
|
||||
<None Include="Doc\SQLite.NET.chm" />
|
||||
<Content Include="Website\locales\cs.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\de.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\en.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\es.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\fr.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\it.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\nl.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\pt.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\sv.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\locales\tr.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Doc\Roadmap.txt" />
|
||||
<Content Include="Vocaluxe.ico" />
|
||||
<Content Include="Website\css\images\ajax-loader.gif">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>images</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\css\images\alert.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\css\images\icons-18-black.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>images</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\css\images\icons-18-white.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>images</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\css\images\icons-36-black.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>images</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\css\images\icons-36-white.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>images</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\css\jquery.mobile-1.3.2.min.css">
|
||||
<CustomToolNamespace>css</CustomToolNamespace>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\css\jquery.mobile.theme-1.3.2.min.css">
|
||||
<CustomToolNamespace>css</CustomToolNamespace>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\css\style.css">
|
||||
<CustomToolNamespace>css</CustomToolNamespace>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\addPlaylist.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\logout.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\music.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\noCover.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\playlist.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\playlists.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\spotify.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\wikipedia.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\youtube.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\index.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\img\admin.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>img</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\img\keyboard.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>img</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\img\photo.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>img</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\img\profile.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>img</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\img\profiles.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>img</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\js\i18next-1.7.1.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\js\jquery-1.9.1.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CustomToolNamespace>js</CustomToolNamespace>
|
||||
</Content>
|
||||
<Content Include="Website\js\jquery-ui-1.10.3.custom.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\js\jquery.mobile-1.3.2.min.js">
|
||||
<CustomToolNamespace>js</CustomToolNamespace>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\js\jquery.ui.touch-punch.min.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Website\js\main.js">
|
||||
<CustomToolNamespace>js</CustomToolNamespace>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client,KB2468871">
|
||||
@@ -524,12 +382,10 @@
|
||||
<Project>{D2B6DDEF-E0E1-4DDF-A73A-E6ACEF5C95EC}</Project>
|
||||
<Name>VocaluxeLib</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Website\html\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<WCFMetadata Include="Service References\" />
|
||||
<ProjectReference Include="..\VocaluxeWeb\VocaluxeWeb.csproj" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'">
|
||||
<Project>{4E2C9A71-6B3D-4F85-9C1E-8A7D5B2F3C60}</Project>
|
||||
<Name>VocaluxeWeb</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Reporting\Reporter.resx">
|
||||
@@ -538,10 +394,8 @@
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">xcopy /E /D /Y "$(ProjectDir)\Website" "$(SolutionDir)\PhoneGap"
|
||||
powershell -ExecutionPolicy Bypass -Command "& '$(SolutionDir)\.build\winPostBuild.ps1' -ProjectDir '$(ProjectDir)'"</PostBuildEvent>
|
||||
<PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">cp -ruT "$(ProjectDir)Website" "$(SolutionDir)/PhoneGap"
|
||||
$(SolutionDir)/.build/linuxPostBuildEvent.sh $(ProjectDir)</PostBuildEvent>
|
||||
<PostBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">powershell -ExecutionPolicy Bypass -Command "& '$(SolutionDir)\.build\winPostBuild.ps1' -ProjectDir '$(ProjectDir)'"</PostBuildEvent>
|
||||
<PostBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">$(SolutionDir)/.build/linuxPostBuildEvent.sh $(ProjectDir)</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent Condition=" '$(OS)' == 'Windows_NT' ">powershell -ExecutionPolicy Bypass -Command "& '$(SolutionDir)\.build\winPreBuild.ps1' -ProjectDir '$(ProjectDir)' -Arch '$(Platform)'"</PreBuildEvent>
|
||||
@@ -568,11 +422,23 @@ $(SolutionDir)/.build/linuxPostBuildEvent.sh $(ProjectDir)</PostBuildEvent>
|
||||
PostBuildMacros;
|
||||
</PostBuildEventDependsOn>
|
||||
</PropertyGroup>
|
||||
<Target Name="copyWebAppAfterBuild" BeforeTargets="AfterBuild" Condition="'$(Configuration)' != 'ReleaseLinux' AND '$(Configuration)' != 'DebugLinux'">
|
||||
<Message Text="copy the WebApp (built by VocaluxeWeb) to the Website folder" Importance="normal" />
|
||||
<ItemGroup>
|
||||
<WebAppFiles Include="$(ProjectDir)..\WebApp\dist\**\*" />
|
||||
</ItemGroup>
|
||||
<RemoveDir Directories="$(TargetDir)Website" />
|
||||
<Copy SourceFiles="@(WebAppFiles)" DestinationFiles="@(WebAppFiles->'$(TargetDir)Website\%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
</Target>
|
||||
<Target Name="managedDepCopyAfterBuild" BeforeTargets="AfterBuild">
|
||||
<Message Text="move all libs to the managed dependencies folder" Importance="normal" />
|
||||
<ItemGroup>
|
||||
<RootDLLFilesToMove Include="$(TargetDir)*.dll" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<RootDLLCompanionFiles Include="@(RootDLLFilesToMove->'%(RootDir)%(Directory)%(Filename).pdb');@(RootDLLFilesToMove->'%(RootDir)%(Directory)%(Filename).xml');@(RootDLLFilesToMove->'%(FullPath).config')" />
|
||||
<OtherFilesToMove Include="@(RootDLLCompanionFiles)" Condition="Exists('%(FullPath)')" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<x64FolderFilesToMove Include="$(TargetDir)x64\*.*" />
|
||||
</ItemGroup>
|
||||
|
||||
|
Before Width: | Height: | Size: 7.6 KiB |
|
Before Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,12 +0,0 @@
|
||||
/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
|
||||
|
||||
/*!
|
||||
* jQuery Mobile 1.3.2
|
||||
* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
|
||||
* http://jquerymobile.com
|
||||
*
|
||||
* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
*/.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:700;text-shadow:0 -1px 0 #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:700}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 0 #111;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:-webkit-linear-gradient(#444,#222);background-image:-moz-linear-gradient(#444,#222);background-image:-ms-linear-gradient(#444,#222);background-image:-o-linear-gradient(#444,#222);background-image:linear-gradient(#444,#222)}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:700}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#2d2d2d));background-image:-webkit-linear-gradient(#444,#2d2d2d);background-image:-moz-linear-gradient(#444,#2d2d2d);background-image:-ms-linear-gradient(#444,#2d2d2d);background-image:-o-linear-gradient(#444,#2d2d2d);background-image:linear-gradient(#444,#2d2d2d)}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#383838));background-image:-webkit-linear-gradient(#555,#383838);background-image:-moz-linear-gradient(#555,#383838);background-image:-ms-linear-gradient(#555,#383838);background-image:-o-linear-gradient(#555,#383838);background-image:linear-gradient(#555,#383838)}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#202020),to(#2c2c2c));background-image:-webkit-linear-gradient(#202020,#2c2c2c);background-image:-moz-linear-gradient(#202020,#2c2c2c);background-image:-ms-linear-gradient(#202020,#2c2c2c);background-image:-o-linear-gradient(#202020,#2c2c2c);background-image:linear-gradient(#202020,#2c2c2c)}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:700;text-shadow:0 1px 0 #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#497bae));background-image:-webkit-linear-gradient(#6facd5,#497bae);background-image:-moz-linear-gradient(#6facd5,#497bae);background-image:-ms-linear-gradient(#6facd5,#497bae);background-image:-o-linear-gradient(#6facd5,#497bae);background-image:linear-gradient(#6facd5,#497bae)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:700}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#ccc));background-image:-webkit-linear-gradient(#ddd,#ccc);background-image:-moz-linear-gradient(#ddd,#ccc);background-image:-ms-linear-gradient(#ddd,#ccc);background-image:-o-linear-gradient(#ddd,#ccc);background-image:linear-gradient(#ddd,#ccc)}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:700}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:700;coloLine truncated
|
||||
@@ -1,12 +0,0 @@
|
||||
/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
|
||||
|
||||
/*!
|
||||
* jQuery Mobile 1.3.2
|
||||
* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
|
||||
* http://jquerymobile.com
|
||||
*
|
||||
* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
|
||||
* Released under the MIT license.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
*/.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:700;text-shadow:0 -1px 0 #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:700}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 0 #111;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:-webkit-linear-gradient(#444,#222);background-image:-moz-linear-gradient(#444,#222);background-image:-ms-linear-gradient(#444,#222);background-image:-o-linear-gradient(#444,#222);background-image:linear-gradient(#444,#222)}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:700}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#2d2d2d));background-image:-webkit-linear-gradient(#444,#2d2d2d);background-image:-moz-linear-gradient(#444,#2d2d2d);background-image:-ms-linear-gradient(#444,#2d2d2d);background-image:-o-linear-gradient(#444,#2d2d2d);background-image:linear-gradient(#444,#2d2d2d)}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#383838));background-image:-webkit-linear-gradient(#555,#383838);background-image:-moz-linear-gradient(#555,#383838);background-image:-ms-linear-gradient(#555,#383838);background-image:-o-linear-gradient(#555,#383838);background-image:linear-gradient(#555,#383838)}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#202020),to(#2c2c2c));background-image:-webkit-linear-gradient(#202020,#2c2c2c);background-image:-moz-linear-gradient(#202020,#2c2c2c);background-image:-ms-linear-gradient(#202020,#2c2c2c);background-image:-o-linear-gradient(#202020,#2c2c2c);background-image:linear-gradient(#202020,#2c2c2c)}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:700;text-shadow:0 1px 0 #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#497bae));background-image:-webkit-linear-gradient(#6facd5,#497bae);background-image:-moz-linear-gradient(#6facd5,#497bae);background-image:-ms-linear-gradient(#6facd5,#497bae);background-image:-o-linear-gradient(#6facd5,#497bae);background-image:linear-gradient(#6facd5,#497bae)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:700}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#ccc));background-image:-webkit-linear-gradient(#ddd,#ccc);background-image:-moz-linear-gradient(#ddd,#ccc);background-image:-ms-linear-gradient(#ddd,#ccc);background-image:-o-linear-gradient(#ddd,#ccc);background-image:linear-gradient(#ddd,#ccc)}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:700}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:700;coloLine truncated
|
||||
@@ -1,121 +0,0 @@
|
||||
#playerAvatar {
|
||||
height: 75%;
|
||||
max-height: 250px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#playerName {
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#displayProfileContent {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#keyboardContent {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overlay {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background-color: #000000;
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
}
|
||||
|
||||
.ui-loader-background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
margin: 0;
|
||||
background: #000000;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
display: none;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.ui-loading .ui-loader-background {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#displaySongCover {
|
||||
height: 75%;
|
||||
max-height: 250px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#displaySongContent {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#displaySongContent span {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.imageLoaderImg {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: url(images/ajax-loader.gif);
|
||||
background-size: 45px;
|
||||
border: #000000 solid 0px;
|
||||
content: '';
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.ui-body-c, .ui-overlay-c {
|
||||
background: #000000;
|
||||
}
|
||||
|
||||
.ui-input-search {
|
||||
background: #6E6E6E !important;
|
||||
}
|
||||
|
||||
.ui-listview-filter {
|
||||
background: #000000 !important;
|
||||
}
|
||||
|
||||
.ui-custom-errorIcon {
|
||||
background: url(images/alert.png) !important;
|
||||
background-size: 42px 42px;
|
||||
-webkit-border-radius: 0px !important;
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
|
||||
.cursorStyleClickable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#logo {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
width: 219px;
|
||||
height:40px;
|
||||
}
|
||||
|
||||
.ui-bar-b {
|
||||
border: 1px solid #000;
|
||||
border-top-width: 1px;
|
||||
border-right-width: 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-left-width: 1px;
|
||||
background: #000;
|
||||
background-image: none;
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 1px 0 #3e6790;
|
||||
background-image: -webkit-gradient(linear,left top,left bottom,from(#000000),to(#000000));
|
||||
background-image: -webkit-linear-gradient(#000000,#000000);
|
||||
background-image: -moz-linear-gradient(#000000,#000000);
|
||||
background-image: -ms-linear-gradient(#000000,#000000);
|
||||
background-image: -o-linear-gradient(#000000,#000000);
|
||||
background-image: linear-gradient(#000000,#000000);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 8.7 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
@@ -1,5 +0,0 @@
|
||||
100% royalty-free icons from flaticons.net
|
||||
|
||||
https://flaticons.net
|
||||
|
||||
For: personal, commercial use, without attribution
|
||||
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 8.8 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 628 B |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 268 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
@@ -1,381 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Vocaluxe</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/jquery.mobile-1.3.2.min.css" />
|
||||
<link rel="stylesheet" href="css/style.css" />
|
||||
<script src="js/jquery-1.9.1.min.js"></script>
|
||||
<script>
|
||||
if (document.location.protocol == "file:") {
|
||||
if (typeof (window.deviceAndJqmLoaded) == "undefined") {
|
||||
window.deviceAndJqmLoaded = $.Deferred();
|
||||
}
|
||||
var jqmready = $.Deferred();
|
||||
var deviceready = $.Deferred();
|
||||
|
||||
$(document).bind("mobileinit", function () {
|
||||
jqmready.resolve();
|
||||
});
|
||||
|
||||
function deviceIsReady() {
|
||||
deviceready.resolve();
|
||||
}
|
||||
|
||||
document.addEventListener("deviceready", deviceIsReady, false);
|
||||
|
||||
$.when(jqmready, deviceready).then(function () {
|
||||
window.deviceAndJqmLoaded.resolve();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="js/jquery.mobile-1.3.2.min.js"></script>
|
||||
<script src="js/jquery-ui-1.10.3.custom.min.js"></script>
|
||||
<script src="js/jquery.ui.touch-punch.min.js"></script>
|
||||
<script src="js/i18next-1.7.1.min.js"></script>
|
||||
<script src="js/main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="login" data-content-theme="a" data-role="page" data-add-back-btn="false">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="">Login</h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="loginContent" data-role="content">
|
||||
<label for="loginName" class="input" data-i18n="loginName"></label>
|
||||
<input type="text" id="loginName" name="loginName" data-mini="true">
|
||||
<label for="loginPassword" class="input" data-i18n="loginPassword"></label>
|
||||
<input type="password" id="loginPassword" name="loginPassword" data-mini="true">
|
||||
<br />
|
||||
<a data-role="button" id="loginButton" data-i18n="loginButton"></a>
|
||||
<br />
|
||||
<hr />
|
||||
<br />
|
||||
<a data-role="button" id="registerButton" data-i18n="registerButton"></a>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="main" data-role="page" data-content-theme="a" data-add-back-btn="false">
|
||||
<div data-role="header">
|
||||
<img id="logo" src="img/logo.png" alt="Vocaluxe logo">
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="mainContent" data-role="content" data-add-back-btn="true">
|
||||
<ul data-role="listview">
|
||||
<li>
|
||||
<a id="yourProfileLink" href="#" data-transition="slidefade">
|
||||
<img src="img/profile.png">
|
||||
<h2 data-i18n="mainPageYourProfileLink"></h2>
|
||||
<p data-i18n="mainPageYourProfileLinkDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="currentSongLink" href="#" data-transition="slidefade">
|
||||
<img src="img/music.png">
|
||||
<h2 data-i18n="mainPageCurrentSongLink"></h2>
|
||||
<p data-i18n="mainPageCurrentSongLinkDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#selectSong" data-transition="slidefade">
|
||||
<img src="img/playlist.png">
|
||||
<h2 data-i18n="mainPageSelectSong"></h2>
|
||||
<p data-i18n="mainPageSelectSongDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#selectPlaylist" data-transition="slidefade">
|
||||
<img src="img/playlists.png">
|
||||
<h2 data-i18n="mainPageSelectPlaylist"></h2>
|
||||
<p data-i18n="mainPageSelectPlaylistDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="mainPageSelectProfile" href="#selectProfile" data-transition="slidefade">
|
||||
<img src="img/profiles.png">
|
||||
<h2 data-i18n="mainPageSelectProfile"></h2>
|
||||
<p data-i18n="mainPageSelectProfileDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="mainPageTakePhotoLink" href="#" data-transition="slidefade">
|
||||
<img src="img/photo.png">
|
||||
<h2 data-i18n="mainPageTakePhotoLink"></h2>
|
||||
<p data-i18n="mainPageTakePhotoLinkDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="mainPageKeyboard" href="#keyboard" data-transition="slidefade">
|
||||
<img src="img/keyboard.png">
|
||||
<h2 data-i18n="mainPageKeyboard"></h2>
|
||||
<p data-i18n="mainPageKeyboardDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#selectUserAdmin" data-transition="slidefade">
|
||||
<img src="img/admin.png">
|
||||
<h2 data-i18n="mainPageSelectUserAdmin"></h2>
|
||||
<p data-i18n="mainPageSelectUserAdminDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a id="mainPageLogoutLink" href="#" data-transition="slidefade">
|
||||
<img src="img/logout.png">
|
||||
<h2 data-i18n="mainPageLogoutLink"></h2>
|
||||
<p data-i18n="mainPageLogoutLinkDesc"></p>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="selectProfile" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="selectProfileHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="selectProfileContent" data-role="content">
|
||||
<ul id="selectProfileList" data-role="listview"></ul>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="displayProfile" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="displayProfileHeader">Profile</h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="displayProfileContent" data-role="content">
|
||||
<img id="playerAvatar" src="img/profile.png" alt="Avatar">
|
||||
<label for="playerName" class="input" data-i18n="displayProfileName"></label>
|
||||
<input type="text" id="playerName" name="playerName" data-mini="true" value="Your Name">
|
||||
|
||||
<label for="playerType" class="select" data-i18n="displayProfilePlayerType"></label>
|
||||
<select name="playerType" id="playerType">
|
||||
<option value="0" data-i18n="displayProfilePlayerTypeNormal"></option>
|
||||
<option value="1" data-i18n="displayProfilePlayerTypeGuest"></option>
|
||||
</select>
|
||||
<label for="playerDifficulty" class="select" data-i18n="displayProfilePlayerDifficulty"></label>
|
||||
<select name="playerDifficulty" id="playerDifficulty">
|
||||
<option value="0" data-i18n="displayProfilePlayerDifficultyEasy"></option>
|
||||
<option value="1" data-i18n="displayProfilePlayerDifficultyNormal"></option>
|
||||
<option value="2" data-i18n="displayProfilePlayerDifficultyHard"></option>
|
||||
</select>
|
||||
|
||||
<label id="playerPasswordLabel" for="playerPassword" class="input" data-i18n="displayProfilePlayerPassword"></label>
|
||||
<input type="password" id="playerPassword" name="playerPassword" data-mini="true" value="**oldPassword**">
|
||||
|
||||
<br />
|
||||
<a data-role="button" id="playerSaveButton" data-i18n="displayProfilePlayerSaveButton"></a>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="displaySong" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 id="displaySongTitle" data-i18n="displaySongHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="displaySongContent" data-role="content">
|
||||
<img id="displaySongCover" src="img/noCover.png" alt="Cover">
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<label for="displaySongArtist" class="input" data-i18n="displaySongArtist"></label>
|
||||
<span id="displaySongArtist" data-mini="true">-</span>
|
||||
<br />
|
||||
<label for="displaySongGenre" class="input" data-i18n="displaySongGenre"></label>
|
||||
<span id="displaySongGenre" data-mini="true">-</span>
|
||||
<br />
|
||||
<label for="displaySongYear" class="input" data-i18n="displaySongYear"></label>
|
||||
<span id="displaySongYear" data-mini="true">-</span>
|
||||
<br />
|
||||
<label for="displaySongLanguage" class="input" data-i18n="displaySongLanguage"></label>
|
||||
<span id="displaySongLanguage" data-mini="true">-</span>
|
||||
<br />
|
||||
<label for="displaySongIsDuet" class="input" data-i18n="displaySongIsDuet"></label>
|
||||
<span id="displaySongIsDuet" data-mini="true">-</span>
|
||||
<br />
|
||||
<br />
|
||||
<div id="displaySongLinks">
|
||||
<img class="cursorStyleClickable" id="displaySongAddPlaylist" src="img/addPlaylist.png" />
|
||||
<br />
|
||||
<audio controls id="displaySongPlayer" preload="none"></audio>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!-- /content -->
|
||||
<div data-role="popup" id="popupVideo" data-overlay-theme="a" data-theme="a" data-corners="false" data-tolerance="15,15">
|
||||
<a href="#" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-right" data-i18n="popupVideoClose"></a>
|
||||
<iframe width="480" height="320" seamless></iframe>
|
||||
</div>
|
||||
<!-- /popup -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="selectSong" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="selectSongHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="selectSongContent" data-role="content">
|
||||
<ul id="selectSongList" data-role="listview" data-filter="true" data-autodividers="true"></ul>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="keyboard" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="keyboardHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="keyboardContent" data-role="content">
|
||||
<div class="ui-grid-b">
|
||||
<div class="ui-block-a"></div>
|
||||
<div class="ui-block-b">
|
||||
<a data-role="button" id="keyboardButtonUp" data-i18n="keyboardButtonUp"></a>
|
||||
</div>
|
||||
<div class="ui-block-c"></div>
|
||||
<div class="ui-block-a">
|
||||
<a data-role="button" id="keyboardButtonLeft" data-i18n="keyboardButtonLeft"></a>
|
||||
</div>
|
||||
<div class="ui-block-b">
|
||||
</div>
|
||||
<div class="ui-block-c">
|
||||
<a data-role="button" id="keyboardButtonRight" data-i18n="keyboardButtonRight"></a>
|
||||
</div>
|
||||
<div class="ui-block-a"></div>
|
||||
<div class="ui-block-b">
|
||||
<a data-role="button" id="keyboardButtonDown" data-i18n="keyboardButtonDown"></a>
|
||||
</div>
|
||||
<div class="ui-block-c"></div>
|
||||
</div>
|
||||
<div class="ui-grid-b">
|
||||
<div class="ui-block-a">
|
||||
<a data-role="button" id="keyboardButtonEscape" data-i18n="keyboardButtonEscape"></a>
|
||||
</div>
|
||||
<div class="ui-block-b">
|
||||
<a data-role="button" id="keyboardButtonTab" data-i18n="keyboardButtonTab"></a>
|
||||
</div>
|
||||
<div class="ui-block-c">
|
||||
<a data-role="button" id="keyboardButtonReturn" data-i18n="keyboardButtonReturn"></a>
|
||||
</div>
|
||||
<div class="ui-block-a">
|
||||
<!--
|
||||
<fieldset data-role="controlgroup" data-type="horizontal">
|
||||
<input type="checkbox" name="keyboardButtonFunct" id="keyboardButtonFunct" />
|
||||
<label data-i18n="keyboardButtonFunct" for="keyboardButtonFunct"></label>
|
||||
</fieldset>-->
|
||||
</div>
|
||||
<div class="ui-block-b">
|
||||
<fieldset data-role="controlgroup" data-type="horizontal">
|
||||
<input type="checkbox" name="keyboardButtonShift" id="keyboardButtonShift" />
|
||||
<label data-i18n="keyboardButtonShift" for="keyboardButtonShift"></label>
|
||||
<input type="checkbox" name="keyboardButtonAlt" id="keyboardButtonAlt" />
|
||||
<label data-i18n="keyboardButtonAlt" for="keyboardButtonAlt"></label>
|
||||
<input type="checkbox" name="keyboardButtonCtrl" id="keyboardButtonCtrl" />
|
||||
<label data-i18n="keyboardButtonCtrl" for="keyboardButtonCtrl"></label>
|
||||
</fieldset>
|
||||
</div>
|
||||
<div class="ui-block-c">
|
||||
<a data-role="button" id="keyboardButtonBackspace" data-i18n="keyboardButtonBackspace"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<fieldset data-role="controlgroup" data-type="horizontal">
|
||||
<input type="checkbox" name="keyboardAutoSend" id="keyboardAutoSend" />
|
||||
<label data-i18n="keyboardAutoSend" for="keyboardAutoSend"></label>
|
||||
</fieldset>
|
||||
<label for="keyboardButtonKeys" data-i18n="keyboardButtonKeys"></label>
|
||||
<input type="text" id="keyboardButtonKeys" data-mini="true">
|
||||
<a data-role="button" id="keyboardButtonSend" data-i18n="keyboardButtonSend"></a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="selectUserAdmin" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="selectUserAdminHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="selectUserAdminContent" data-role="content">
|
||||
<ul id="selectUserAdminList" data-role="listview"></ul>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="displayUserAdmin" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="displayUserAdminHeader"></h1>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="displayUserAdminContent" data-role="content">
|
||||
<fieldset data-role="controlgroup">
|
||||
<legend></legend>
|
||||
<input type="checkbox" id="TR_USERROLE_ADMIN">
|
||||
<label for="TR_USERROLE_ADMIN">Administrator</label>
|
||||
<input type="checkbox" id="TR_USERROLE_KEYBOARDUSER">
|
||||
<label for="TR_USERROLE_KEYBOARDUSER">Keyboard</label>
|
||||
<input type="checkbox" id="TR_USERROLE_ADDSONGSUSER">
|
||||
<label for="TR_USERROLE_ADDSONGSUSER">AddSongs</label>
|
||||
<input type="checkbox" id="TR_USERROLE_PLAYLISTEDITOR">
|
||||
<label for="TR_USERROLE_PLAYLISTEDITOR">PlaylistEditor</label>
|
||||
<input type="checkbox" id="TR_USERROLE_PROFILEEDITOR">
|
||||
<label for="TR_USERROLE_PROFILEEDITOR">ProfileEditor</label>
|
||||
</fieldset>
|
||||
<a data-role="button" id="btnRoleSave" data-transition="slidefade" data-i18n="displayUserAdminContentSaveButton"></a>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="selectPlaylist" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div data-role="header">
|
||||
<h1 data-i18n="selectPlaylistHeader"></h1>
|
||||
<a id="selectPlaylistAddPlaylistButton" href="#" class="ui-btn-right" data-icon="add" data-i18n="selectPlaylistAddPlaylistButton"></a>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="selectPlaylistContent" data-role="content">
|
||||
<ul data-split-theme="a" id="selectPlaylistContentList" data-role="listview" data-filter="true"></ul>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div id="displayPlaylist" data-content-theme="a" data-role="page" data-add-back-btn="true">
|
||||
<div id="displayPlaylistHeader" data-role="header">
|
||||
<h1 data-i18n="displayPlaylistHeader"></h1>
|
||||
<a id="displayPlaylistSaveButton" class="ui-btn-right" href="#" data-icon="add" data-i18n="displayPlaylistSaveButton"></a>
|
||||
</div>
|
||||
<!-- /header -->
|
||||
|
||||
<div id="displayPlaylistContent" data-role="content">
|
||||
<ol data-split-theme="a" id="displayPlaylistContentList" data-role="listview" data-filter="true"></ol>
|
||||
</div>
|
||||
<!-- /content -->
|
||||
</div>
|
||||
<!-- /page -->
|
||||
|
||||
<div class="ui-loader-background"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
// i18next, v1.7.1
|
||||
// Copyright (c)2013 Jan Mühlemann (jamuhl).
|
||||
// Distributed under MIT license
|
||||
// http://i18next.com
|
||||
!function(){function a(a,b){if(!b||"function"==typeof b)return a;for(var c in b)a[c]=b[c];return a}function b(a,b,c){var d,e=0,f=a.length,g=void 0===f||"function"==typeof a;if(c)if(g){for(d in a)if(b.apply(a[d],c)===!1)break}else for(;f>e&&b.apply(a[e++],c)!==!1;);else if(g){for(d in a)if(b.call(a[d],d,a[d])===!1)break}else for(;f>e&&b.call(a[e],e,a[e++])!==!1;);return a}function c(a){return"string"==typeof a?a.replace(/[&<>"'\/]/g,function(a){return H[a]}):a}function d(a){var b=function(a){if(window.XMLHttpRequest)return a(null,new XMLHttpRequest);if(window.ActiveXObject)try{return a(null,new ActiveXObject("Msxml2.XMLHTTP"))}catch(b){return a(null,new ActiveXObject("Microsoft.XMLHTTP"))}return a(new Error)},c=function(a){if("string"==typeof a)return a;var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(encodeURIComponent(c)+"="+encodeURIComponent(a[c]));return b.join("&")},d=function(a){a=a.replace(/\r\n/g,"\n");for(var b="",c=0;c<a.length;c++){var d=a.charCodeAt(c);128>d?b+=String.fromCharCode(d):d>127&&2048>d?(b+=String.fromCharCode(192|d>>6),b+=String.fromCharCode(128|63&d)):(b+=String.fromCharCode(224|d>>12),b+=String.fromCharCode(128|63&d>>6),b+=String.fromCharCode(128|63&d))}return b},e=function(a){var b="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";a=d(a);var c,e,f,g,h,i,j,k="",l=0;do c=a.charCodeAt(l++),e=a.charCodeAt(l++),f=a.charCodeAt(l++),g=c>>2,h=(3&c)<<4|e>>4,i=(15&e)<<2|f>>6,j=63&f,isNaN(e)?i=j=64:isNaN(f)&&(j=64),k+=b.charAt(g)+b.charAt(h)+b.charAt(i)+b.charAt(j),c=e=f="",g=h=i=j="";while(l<a.length);return k},f=function(){for(var a=arguments[0],b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)c.hasOwnProperty(d)&&(a[d]=c[d])}return a},g=function(a,d,e,h){"function"==typeof e&&(h=e,e={}),e.cache=e.cache||!1,e.data=e.data||{},e.headers=e.headers||{},e.jsonp=e.jsonp||!1,e.async=void 0===e.async?!0:e.async;var i,j=f({accept:"*/*","content-type":"application/x-www-form-urlencoded;charset=UTF-8"},g.headers,e.headers);if(i="application/json"===j["content-type"]?JSON.stringify(e.data):c(e.data),"GET"===a){var k=[];if(i&&(k.push(i),i=null),e.cache||k.push("_="+(new Date).getTime()),e.jsonp&&(k.push("callback="+e.jsonp),k.push("jsonp="+e.jsonp)),k=k.join("&"),k.length>1&&(d+=d.indexOf("?")>-1?"&"+k:"?"+k),e.jsonp){var l=document.getElementsByTagName("head")[0],m=document.createElement("script");return m.type="text/javascript",m.src=d,l.appendChild(m),void 0}}b(function(b,c){if(b)return h(b);c.open(a,d,e.async);for(var f in j)j.hasOwnProperty(f)&&c.setRequestHeader(f,j[f]);c.onreadystatechange=function(){if(4===c.readyState){var a=c.responseText||"";if(!h)return;h(c.status,{text:function(){return a},json:function(){return JSON.parse(a)}})}},c.send(i)})},h={authBasic:function(a,b){g.headers.Authorization="Basic "+e(a+":"+b)},connect:function(a,b,c){return g("CONNECT",a,b,c)},del:function(a,b,c){return g("DELETE",a,b,c)},get:function(a,b,c){return g("GET",a,b,c)},head:function(a,b,c){return g("HEAD",a,b,c)},headers:function(a){g.headers=a||{}},isAllowed:function(a,b,c){this.options(a,function(a,d){c(-1!==d.text().indexOf(b))})},options:function(a,b,c){return g("OPTIONS",a,b,c)},patch:function(a,b,c){return g("PATCH",a,b,c)},post:function(a,b,c){return g("POST",a,b,c)},put:function(a,b,c){return g("PUT",a,b,c)},trace:function(a,b,c){return g("TRACE",a,b,c)}},i=a.type?a.type.toLowerCase():"get";h[i](a.url,a,function(b,c){200===b?a.success(c.json(),b,null):a.error(c.text(),b,null)})}function e(a,b){"function"==typeof a&&(b=a,a={}),a=a||{},K.extend(G,a),delete G.fixLng,"string"==typeof G.ns&&(G.ns={namespaces:[G.ns],defaultNs:G.ns}),"string"==typeof G.fallbackNS&&(G.fallbackNS=[G.fallbackNS]),G.interpolationPrefixEscaped=K.regexEscape(G.interpolationPrefix),G.interpolationSuffixEscaped=K.regexEscape(G.interpolationSuffix),G.lng||(G.lng=K.detectLanguage()),G.lng?G.useCookie&&K.cookie.create(G.cookieName,G.lng,G.cookieExpirationTime,G.cookieDomain):(G.lng=G.fallbackLng,G.useCookie&&K.cookie.remove(G.cookieName)),E=K.toLanguages(G.lng),y=E[0],K.log("currentLng set to: "+y);var c=s;a.fixLng&&(c=function(a,b){return b=b||{},b.lng=b.lng||c.lng,s(a,b)},c.lng=y),M.setCurrentLng(y),A&&G.setJqueryExt&&m();var d;if(A&&A.Deferred&&(d=A.Deferred()),!G.resStore){var e=K.toLanguages(G.lng);"string"==typeof G.preload&&(G.preload=[G.preload]);for(var f=0,g=G.preload.length;g>f;f++)for(var h=K.toLanguages(G.preload[f]),i=0,j=h.length;j>i;i++)e.indexOf(h[i])<0&&e.push(h[i]);return B.sync.load(e,G,function(a,e){C=e,F=!0,b&&b(c),d&&d.resolve(c)}),d?d.promise():void 0}return C=G.resStore,F=!0,b&&b(c),d&&d.resolve(c),d?d.promise():void 0}function f(a,b){"string"==typeof a&&(a=[a]);for(var c=0,d=a.length;d>c;c++)G.preload.indexOf(a[c])<0&&G.preload.push(a[c]);return e(b)}function g(a,b,c){"string"!=typeof b?(c=b,b=G.ns.defaultNs):G.ns.namespaces.indexOf(b)<0&&G.ns.namespaces.push(b),C[a]=C[a]||{},C[a][b]=C[a][b]||{},K.extend(C[a][b],c)}function h(a){G.ns.defaultNs=a}function i(a,b){j([a],b)}funLine truncated
|
||||
@@ -1,5 +0,0 @@
|
||||
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
||||
//@ sourceMappingURL=jquery.min.map
|
||||
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
||||
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
||||
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
||||
@@ -1,6 +0,0 @@
|
||||
/*! jQuery UI - v1.10.3 - 2013-11-03
|
||||
* http://jqueryui.com
|
||||
* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.sortable.js
|
||||
* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */
|
||||
|
||||
(function(e,t){function i(t,i){var s,n,r,o=t.nodeName.toLowerCase();return"area"===o?(s=t.parentNode,n=s.name,t.href&&n&&"map"===s.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&a(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&a(t)}function a(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var s=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.3",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,a){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),a&&a.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var a,s,n=e(this[0]);n.length&&n[0]!==document;){if(a=n.css("position"),("absolute"===a||"relative"===a||"fixed"===a)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++s)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,a){return!!e.data(t,a[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var a=e.attr(t,"tabindex"),s=isNaN(a);return(s||a>=0)&&i(t,!s)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,a){function s(t,i,a,s){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,a&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===a?["Left","Right"]:["Top","Bottom"],r=a.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+a]=function(i){return i===t?o["inner"+a].call(this):this.each(function(){e(this).css(r,s(this,i)+"px")})},e.fn["outer"+a]=function(t,i){return"number"!=typeof t?o["outer"+a].call(this,t):this.each(function(){e(this).css(r,s(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,a){var s,n=e.ui[t].prototype;for(s in a)n.plugins[s]=n.plugins[s]||[],n.plugins[s].push([i,a[s]])},call:function(e,t,i){var a,s=e.plugins[t];if(s&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(a=0;s.length>a;a++)e.options[s[a][0]]&&s[a][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var a=i&&"left"===i?"scrollLeft":"scrollTop",s=!1;return t[a]>0?!0:(t[a]=1,s=t[a]>0,t[a]=0,s)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,a=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(n){}a(t)},e.widget=function(i,s,a){var n,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],n=u+"-"+i,a||(a=s,s=e.Widget),e.expr[":"][n.toLowerCase()]=function(t){return!!e.data(t,n)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:a.version,_proto:e.extend({},a),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(a,function(i,a){return e.isFunction(a)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,n=this._superApply;return this._suLine truncated
|
||||
@@ -1,9 +0,0 @@
|
||||
/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
|
||||
!function(a,b,c){"function"==typeof define&&define.amd?define(["jquery"],function(d){return c(d,a,b),d.mobile}):c(a.jQuery,a,b)}(this,document,function(a,b,c,d){!function(a){a.mobile={}}(a),function(a,b,d){var e={};a.mobile=a.extend(a.mobile,{version:"1.3.2",ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:!0,hashListeningEnabled:!0,linkBindingEnabled:!0,defaultPageTransition:"fade",maxTransitionWidth:!1,minScrollBack:250,touchOverflowEnabled:!1,defaultDialogTransition:"pop",pageLoadErrorMessage:"Error Loading Page",pageLoadErrorMessageTheme:"e",phonegapNavigationEnabled:!1,autoInitializePage:!0,pushStateEnabled:!0,ignoreContentEnabled:!1,orientationChangeEnabled:!0,buttonMarkup:{hoverDelay:200},window:a(b),document:a(c),keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},behaviors:{},silentScroll:function(c){"number"!==a.type(c)&&(c=a.mobile.defaultHomeScroll),a.event.special.scrollstart.enabled=!1,setTimeout(function(){b.scrollTo(0,c),a.mobile.document.trigger("silentscroll",{x:0,y:c})},20),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},nsNormalizeDict:e,nsNormalize:function(b){return b?e[b]||(e[b]=a.camelCase(a.mobile.ns+b)):void 0},getInheritedTheme:function(a,b){for(var c,d,e=a[0],f="",g=/ui-(bar|body|overlay)-([a-z])\b/;e&&(c=e.className||"",!(c&&(d=g.exec(c))&&(f=d[2])));)e=e.parentNode;return f||b||"a"},closestPageData:function(a){return a.closest(':jqmData(role="page"), :jqmData(role="dialog")').data("mobile-page")},enhanceable:function(a){return this.haveParents(a,"enhance")},hijackable:function(a){return this.haveParents(a,"ajax")},haveParents:function(b,c){if(!a.mobile.ignoreContentEnabled)return b;for(var d,e,f,g=b.length,h=a(),i=0;g>i;i++){for(e=b.eq(i),f=!1,d=b[i];d;){var j=d.getAttribute?d.getAttribute("data-"+a.mobile.ns+c):"";if("false"===j){f=!0;break}d=d.parentNode}f||(h=h.add(e))}return h},getScreenHeight:function(){return b.innerHeight||a.mobile.window.height()}},a.mobile),a.fn.jqmData=function(b,c){var e;return"undefined"!=typeof b&&(b&&(b=a.mobile.nsNormalize(b)),e=arguments.length<2||c===d?this.data(b):this.data(b,c)),e},a.jqmData=function(b,c,d){var e;return"undefined"!=typeof c&&(e=a.data(b,c?a.mobile.nsNormalize(c):c,d)),e},a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))},a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))},a.fn.removeWithDependents=function(){a.removeWithDependents(this)},a.removeWithDependents=function(b){var c=a(b);(c.jqmData("dependents")||a()).remove(),c.remove()},a.fn.addDependents=function(b){a.addDependents(a(this),b)},a.addDependents=function(b,c){var d=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(d,c))},a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()},a.fn.jqmEnhanceable=function(){return a.mobile.enhanceable(this)},a.fn.jqmHijackable=function(){return a.mobile.hijackable(this)};var f=a.find,g=/:jqmData\(([^)]*)\)/g;a.find=function(b,c,d,e){return b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]"),f.call(this,b,c,d,e)},a.extend(a.find,f),a.find.matches=function(b,c){return a.find(b,null,null,c)},a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}}(a,this),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i=b.split(".")[0];b=b.split(".")[1],e=i+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[i]=a[i]||{},f=a[i][b],g=a[i][b]=function(a,b){return this._createWidget?(arguments.length&&this._createWidget(a,b),void 0):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,e){a.isFunction(e)&&(d[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},d=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=d,b=e.apply(this,arguments),this._super=c,this._superApply=f,b}}())}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},d,{constructor:g,namespace:i,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasLine truncated
|
||||
}if(d.which&&1!==d.which)return!1;var j,k=d.target;d.originalEvent,c.bind("vmouseup",g).bind("vclick",i),f.bind("vmousecancel",h),j=setTimeout(function(){e(b,"taphold",a.Event("taphold",{target:k}))},a.event.special.tap.tapholdThreshold)})}},a.event.special.swipe={scrollSupressionThreshold:30,durationThreshold:1e3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,start:function(b){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;return{time:(new Date).getTime(),coords:[c.pageX,c.pageY],origin:a(b.target)}},stop:function(a){var b=a.originalEvent.touches?a.originalEvent.touches[0]:a;return{time:(new Date).getTime(),coords:[b.pageX,b.pageY]}},handleSwipe:function(b,c){c.time-b.time<a.event.special.swipe.durationThreshold&&Math.abs(b.coords[0]-c.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(b.coords[1]-c.coords[1])<a.event.special.swipe.verticalDistanceThreshold&&b.origin.trigger("swipe").trigger(b.coords[0]>c.coords[0]?"swipeleft":"swiperight")},setup:function(){var b=this,c=a(b);c.bind(i,function(b){function e(b){g&&(f=a.event.special.swipe.stop(b),Math.abs(g.coords[0]-f.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&b.preventDefault())}var f,g=a.event.special.swipe.start(b);c.bind(k,e).one(j,function(){c.unbind(k,e),g&&f&&a.event.special.swipe.handleSwipe(g,f),g=f=d})})}},a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})}(a,this),function(a){a.event.special.throttledresize={setup:function(){a(this).bind("resize",f)},teardown:function(){a(this).unbind("resize",f)}};var b,c,d,e=250,f=function(){c=(new Date).getTime(),d=c-g,d>=e?(g=c,a(this).trigger("throttledresize")):(b&&clearTimeout(b),b=setTimeout(f,e-d))},g=0}(a),function(a,b){function d(){var a=e();a!==f&&(f=a,i.trigger(j))}var e,f,g,h,i=a(b),j="orientationchange",k={0:!0,180:!0};if(a.support.orientation){var l=b.innerWidth||i.width(),m=b.innerHeight||i.height(),n=50;g=l>m&&l-m>n,h=k[b.orientation],(g&&h||!g&&!h)&&(k={"-90":!0,90:!0})}a.event.special.orientationchange=a.extend({},a.event.special.orientationchange,{setup:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(f=e(),i.bind("throttledresize",d),void 0)},teardown:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(i.unbind("throttledresize",d),void 0)},add:function(a){var b=a.handler;a.handler=function(a){return a.orientation=e(),b.apply(this,arguments)}}}),a.event.special.orientationchange.orientation=e=function(){var d=!0,e=c.documentElement;return d=a.support.orientation?k[b.orientation]:e&&e.clientWidth/e.clientHeight<1.1,d?"portrait":"landscape"},a.fn[j]=function(a){return a?this.bind(j,a):this.trigger(j)},a.attrFn&&(a.attrFn[j]=!0)}(a,this),function(a){a.widget("mobile.page",a.mobile.widget,{options:{theme:"c",domCache:!1,keepNativeDefault:":jqmData(role='none'), :jqmData(role='nojs')"},_create:function(){return this._trigger("beforecreate")===!1?!1:(this.element.attr("tabindex","0").addClass("ui-page ui-body-"+this.options.theme),this._on(this.element,{pagebeforehide:"removeContainerBackground",pagebeforeshow:"_handlePageBeforeShow"}),void 0)},_handlePageBeforeShow:function(){this.setContainerBackground()},removeContainerBackground:function(){a.mobile.pageContainer.removeClass("ui-overlay-"+a.mobile.getInheritedTheme(this.element.parent()))},setContainerBackground:function(b){this.options.theme&&a.mobile.pageContainer.addClass("ui-overlay-"+(b||this.options.theme))},keepNativeSelector:function(){var b=this.options,c=b.keepNative&&a.trim(b.keepNative);return c&&b.keepNative!==b.keepNativeDefault?[b.keepNative,b.keepNativeDefault].join(", "):b.keepNativeDefault}})}(a),function(a,b,c){var d=function(d){return d===c&&(d=!0),function(c,e,f,g){var h=new a.Deferred,i=e?" reverse":"",j=a.mobile.urlHistory.getActive(),k=j.lastScroll||a.mobile.defaultHomeScroll,l=a.mobile.getScreenHeight(),m=a.mobile.maxTransitionWidth!==!1&&a.mobile.window.width()>a.mobile.maxTransitionWidth,n=!a.support.cssTransitions||m||!c||"none"===c||Math.max(a.mobile.window.scrollTop(),k)>a.mobile.getMaxScrollForTransition(),o=" ui-page-pre-in",p=function(){a.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-"+c)},q=function(){a.event.special.scrollstart.enabled=!1,b.scrollTo(0,k),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},r=function(){g.removeClass(a.mobile.activePageClass+" out in reverse "+c).height("")},s=function(){d?g.animationComplete(t):t(),g.height(l+a.mobile.window.scrollTop()).addClass(c+" out"+i)},t=function(){g&&d&&r(),u()},u=function(){f.css("z-index",-10),f.addClass(a.mobile.activePageClass+o),a.mobile.focusPage(f),f.height(l+k),q(),f.css("z-index",""),n||f.animationComplete(v),f.removeClass(o).addClass(c+" in"+i),n&&v()},v=function(){d||g&&r(),f.removeClass("out in reverse "+c).height(""),p(),a.mobile.window.scrollTop(Line truncated
|
||||
c.parent().is(":jqmData(role='collapsible-set')")&&c.siblings(".ui-collapsible").trigger("collapse")})},_init:function(){var a=this.element,b=a.children(":jqmData(role='collapsible')"),c=b.filter(":jqmData(collapsed='false')");this._refresh("true"),c.trigger("expand")},_refresh:function(b){var c=this.element.children(":jqmData(role='collapsible')");a.mobile.collapsible.prototype.enhance(c.not(".ui-collapsible")),this._addFirstLastClasses(c,this._getVisibles(c,b),b)},refresh:function(){this._refresh(!1)}},a.mobile.behaviors.addFirstLastClasses)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.collapsibleset.prototype.enhanceWithin(b.target)})}(a),function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br").contents().filter(function(){return 3===this.nodeType&&!/\S/.test(this.nodeValue)}).remove()},a(c).bind("pagecreate create",function(b){a(":jqmData(role='fieldcontain')",b.target).jqmEnhanceable().fieldcontain()})}(a),function(a){a.fn.grid=function(b){return this.each(function(){var c,d=a(this),e=a.extend({grid:null},b),f=d.children(),g={solo:1,a:2,b:3,c:4,d:5},h=e.grid;if(!h)if(f.length<=5)for(var i in g)g[i]===f.length&&(h=i);else h="a",d.addClass("ui-grid-duo");c=g[h],d.addClass("ui-grid-"+h),f.filter(":nth-child("+c+"n+1)").addClass("ui-block-a"),c>1&&f.filter(":nth-child("+c+"n+2)").addClass("ui-block-b"),c>2&&f.filter(":nth-child("+c+"n+3)").addClass("ui-block-c"),c>3&&f.filter(":nth-child("+c+"n+4)").addClass("ui-block-d"),c>4&&f.filter(":nth-child("+c+"n+5)").addClass("ui-block-e")})}}(a),function(a,b){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null,initSelector:":jqmData(role='navbar')"},_create:function(){var d=this.element,e=d.find("a"),f=e.filter(":jqmData(icon)").length?this.options.iconpos:b;d.addClass("ui-navbar ui-mini").attr("role","navigation").find("ul").jqmEnhanceable().grid({grid:this.options.grid}),e.buttonMarkup({corners:!1,shadow:!1,inline:!0,iconpos:f}),d.delegate("a","vclick",function(b){var d=a(b.target).is("a")?a(this):a(this).parent("a");if(!d.is(".ui-disabled, .ui-btn-active")){e.removeClass(a.mobile.activeBtnClass),a(this).addClass(a.mobile.activeBtnClass);var f=a(this);a(c).one("pagehide",function(){f.removeClass(a.mobile.activeBtnClass)})}}),d.closest(".ui-page").bind("pagebeforeshow",function(){e.filter(".ui-state-persist").addClass(a.mobile.activeBtnClass)})}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.navbar.prototype.enhanceWithin(b.target)})}(a),function(a){var b={};a.widget("mobile.listview",a.mobile.widget,a.extend({options:{theme:null,countTheme:"c",headerTheme:"b",dividerTheme:"b",icon:"arrow-r",splitIcon:"arrow-r",splitTheme:"b",corners:!0,shadow:!0,inset:!1,initSelector:":jqmData(role='listview')"},_create:function(){var a=this,b="";b+=a.options.inset?" ui-listview-inset":"",a.options.inset&&(b+=a.options.corners?" ui-corner-all":"",b+=a.options.shadow?" ui-shadow":""),a.element.addClass(function(a,c){return c+" ui-listview"+b}),a.refresh(!0)},_findFirstElementByTagName:function(a,b,c,d){var e={};for(e[c]=e[d]=!0;a;){if(e[a.nodeName])return a;a=a[b]}return null},_getChildrenByTagName:function(b,c,d){var e=[],f={};for(f[c]=f[d]=!0,b=b.firstChild;b;)f[b.nodeName]&&e.push(b),b=b.nextSibling;return a(e)},_addThumbClasses:function(b){var c,d,e=b.length;for(c=0;e>c;c++)d=a(this._findFirstElementByTagName(b[c].firstChild,"nextSibling","img","IMG")),d.length&&(d.addClass("ui-li-thumb"),a(this._findFirstElementByTagName(d[0].parentNode,"parentNode","li","LI")).addClass(d.is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb"))},refresh:function(b){this.parentPage=this.element.closest(".ui-page"),this._createSubPages();var d,e,f,g,h,i,j,k,l,m,n,o,p=this.options,q=this.element,r=q.jqmData("dividertheme")||p.dividerTheme,s=q.jqmData("splittheme"),t=q.jqmData("spliticon"),u=q.jqmData("icon"),v=this._getChildrenByTagName(q[0],"li","LI"),w=!!a.nodeName(q[0],"ol"),x=!a.support.cssPseudoElement,y=q.attr("start"),z={};w&&x&&q.find(".ui-li-dec").remove(),w&&(y||0===y?x?j=parseInt(y,10):(k=parseInt(y,10)-1,q.css("counter-reset","listnumbering "+k)):x&&(j=1)),p.theme||(p.theme=a.mobile.getInheritedTheme(this.element,"c"));for(var A=0,B=v.length;B>A;A++){if(d=v.eq(A),e="ui-li",b||!d.hasClass("ui-li")){f=d.jqmData("theme")||p.theme,g=this._getChildrenByTagName(d[0],"a","A");var C="list-divider"===d.jqmData("role");g.length&&!C?(n=d.jqmData("icon"),d.buttonMarkup({wrapperEls:"div",shadow:!1,corners:!1,iconpos:"right",icon:g.length>1||n===!1?!1:n||u||p.icon,theme:f}),n!==!1&&1===g.length&&d.addClass("ui-li-has-arrow"),g.first().removeClass("ui-link").addClass("ui-link-inherit"),g.length>1&&(e+=" ui-li-has-alt",h=g.last(),i=s||h.jqmData("theme")||p.splitTheme,o=h.jqmData("icon"),h.appendTo(d).attr("title",a.trim(h.getEncodedText())).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:!1,corners:!1,theme:f,icon:!1,iconpos:"notext"}).find(".ui-btn-inner").append(a(c.createElement("span")).Line truncated
|
||||
},_setDisabled:function(a){return this.element.attr("disabled",a),this.button.attr("aria-disabled",a),this._setOption("disabled",a)},_focusButton:function(){var a=this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){var b="";~this.element[0].className.indexOf("ui-btn-left")&&(b=" ui-btn-left"),~this.element[0].className.indexOf("ui-btn-right")&&(b=" ui-btn-right"),this.select=this.element.removeClass("ui-btn-left ui-btn-right").wrap("<div class='ui-select"+b+"'>"),this.selectID=this.select.attr("id"),this.label=a("label[for='"+this.selectID+"']").addClass("ui-select"),this.isMultiple=this.select[0].multiple,this.options.theme||(this.options.theme=a.mobile.getInheritedTheme(this.select,"c"))},_destroy:function(){var a=this.element.parents(".ui-select");a.length>0&&(a.is(".ui-btn-left, .ui-btn-right")&&this.element.addClass(a.is(".ui-btn-left")?"ui-btn-left":"ui-btn-right"),this.element.insertAfter(a),a.remove())},_create:function(){this._preExtension(),this._trigger("beforeCreate"),this.button=this._button();var c=this,d=this.options,e=d.inline||this.select.jqmData("inline"),f=d.mini||this.select.jqmData("mini"),g=d.icon?d.iconpos||this.select.jqmData("iconpos"):!1,h=(-1===this.select[0].selectedIndex?0:this.select[0].selectedIndex,this.button.insertBefore(this.select).buttonMarkup({theme:d.theme,icon:d.icon,iconpos:g,inline:e,corners:d.corners,shadow:d.shadow,iconshadow:d.iconshadow,mini:f}));this.setButtonText(),d.nativeMenu&&b.opera&&b.opera.version&&h.addClass("ui-select-nativeonly"),this.isMultiple&&(this.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(h.addClass("ui-li-has-count"))),(d.disabled||this.element.attr("disabled"))&&this.disable(),this.select.change(function(){c.refresh(),d.nativeMenu&&this.blur()}),this._handleFormReset(),this.build()},build:function(){var b=this;this.select.appendTo(b.button).bind("vmousedown",function(){b.button.addClass(a.mobile.activeBtnClass)}).bind("focus",function(){b.button.addClass(a.mobile.focusClass)}).bind("blur",function(){b.button.removeClass(a.mobile.focusClass)}).bind("focus vmouseover",function(){b.button.trigger("vmouseover")}).bind("vmousemove",function(){b.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){b.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}).bind("change blur",function(){b.button.removeClass("ui-btn-down-"+b.options.theme)}),b.button.bind("vmousedown",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.label.bind("click focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.select.bind("focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.button.bind("mouseup",function(){b.options.preventFocusZoom&&setTimeout(function(){a.mobile.zoom.enable(!0)},0)}),b.select.bind("blur",function(){b.options.preventFocusZoom&&a.mobile.zoom.enable(!0)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var b=this,d=this.selected(),e=this.placeholder,f=a(c.createElement("span"));this.button.find(".ui-btn-text").html(function(){return e=d.length?d.map(function(){return a(this).text()}).get().join(", "):b.placeholder,f.text(e).addClass(b.select.attr("class")).addClass(d.attr("class"))})},setButtonCount:function(){var a=this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},_reset:function(){this.refresh()},refresh:function(){this.setButtonText(),this.setButtonCount()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(!0),this.button.addClass("ui-disabled")},enable:function(){this._setDisabled(!1),this.button.removeClass("ui-disabled")}},a.mobile.behaviors.formReset)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.selectmenu.prototype.enhanceWithin(b.target,!0)})}(a),function(a,d){function e(a,b,c,d){var e=d;return e=b>a?c+(a-b)/2:Math.min(Math.max(c,d-b/2),c+a-b)}function f(){var c=a.mobile.window;return{x:c.scrollLeft(),y:c.scrollTop(),cx:b.innerWidth||c.width(),cy:b.innerHeight||c.height()}}a.widget("mobile.popup",a.mobile.widget,{options:{theme:null,overlayTheme:null,shadow:!0,corners:!0,transition:"none",positionTo:"origin",tolerance:null,initSelector:":jqmData(role='popup')",closeLinkSelector:"a:jqmData(rel='back')",closeLinkEvents:"click.popup",navigateEvents:"navigate.popup",closeEvents:"navigate.popup pagebeforechange.popup",dismissible:!0,history:!a.mobile.browser.oldIE},_eatEventAndClose:function(a){return a.preventDefault(),a.stopImmediatePropagation(),this.options.dismissible&&this.close(),!1},_resizeScreen:function(){var a=this._ui.container.outerHeight(!0);this._ui.screen.removeAttr("style"),a>this._ui.screen.height()&&this._ui.screen.height(a)},_handleWindowKeyUp:function(bLine truncated
|
||||
return c||(d=Math.round(d-a.mobile.window.height()+b.outerHeight())-60),d},_bindScrollWorkaround:function(){var b=this;this._on(a.mobile.window,{scrollstop:function(){var a=b._viewportOffset();a>2&&b._visible&&b._triggerRedraw()}})},_bindListThumbWorkaround:function(){this.element.closest(".ui-page").addClass("ui-android-2x-fixed")},_triggerRedraw:function(){var b=parseFloat(a(".ui-page-active").css("padding-bottom"));a(".ui-page-active").css("padding-bottom",b+1+"px"),setTimeout(function(){a(".ui-page-active").css("padding-bottom",b+"px")},0)},destroy:function(){this._super(),this.element.closest(".ui-page-active").removeClass("ui-android-2x-fix")}})}(a),function(a,d){a.widget("mobile.panel",a.mobile.widget,{options:{classes:{panel:"ui-panel",panelOpen:"ui-panel-open",panelClosed:"ui-panel-closed",panelFixed:"ui-panel-fixed",panelInner:"ui-panel-inner",modal:"ui-panel-dismiss",modalOpen:"ui-panel-dismiss-open",pagePanel:"ui-page-panel",pagePanelOpen:"ui-page-panel-open",contentWrap:"ui-panel-content-wrap",contentWrapOpen:"ui-panel-content-wrap-open",contentWrapClosed:"ui-panel-content-wrap-closed",contentFixedToolbar:"ui-panel-content-fixed-toolbar",contentFixedToolbarOpen:"ui-panel-content-fixed-toolbar-open",contentFixedToolbarClosed:"ui-panel-content-fixed-toolbar-closed",animate:"ui-panel-animate"},animate:!0,theme:"c",position:"left",dismissible:!0,display:"reveal",initSelector:":jqmData(role='panel')",swipeClose:!0,positionFixed:!1},_panelID:null,_closeLink:null,_page:null,_modal:null,_panelInner:null,_wrapper:null,_fixedToolbar:null,_create:function(){var b=this,c=b.element,d=c.closest(":jqmData(role='page')"),e=function(){var b=a.data(d[0],"mobilePage").options.theme,c="ui-body-"+b;return c},f=function(){var a=c.find("."+b.options.classes.panelInner);return 0===a.length&&(a=c.children().wrapAll('<div class="'+b.options.classes.panelInner+'" />').parent()),a},g=function(){var c=d.find("."+b.options.classes.contentWrap);return 0===c.length&&(c=d.children(".ui-header:not(:jqmData(position='fixed')), .ui-content:not(:jqmData(role='popup')), .ui-footer:not(:jqmData(position='fixed'))").wrapAll('<div class="'+b.options.classes.contentWrap+" "+e()+'" />').parent(),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c},h=function(){var c=d.find("."+b.options.classes.contentFixedToolbar);return 0===c.length&&(c=d.find(".ui-header:jqmData(position='fixed'), .ui-footer:jqmData(position='fixed')").addClass(b.options.classes.contentFixedToolbar),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c};a.extend(this,{_panelID:c.attr("id"),_closeLink:c.find(":jqmData(rel='close')"),_page:c.closest(":jqmData(role='page')"),_pageTheme:e(),_panelInner:f(),_wrapper:g(),_fixedToolbar:h()}),b._addPanelClasses(),b._wrapper.addClass(this.options.classes.contentWrapClosed),b._fixedToolbar.addClass(this.options.classes.contentFixedToolbarClosed),b._page.addClass(b.options.classes.pagePanel),a.support.cssTransform3d&&b.options.animate&&this.element.addClass(b.options.classes.animate),b._bindUpdateLayout(),b._bindCloseEvents(),b._bindLinkListeners(),b._bindPageEvents(),b.options.dismissible&&b._createModal(),b._bindSwipeEvents()},_createModal:function(){var b=this;b._modal=a("<div class='"+b.options.classes.modal+"' data-panelid='"+b._panelID+"'></div>").on("mousedown",function(){b.close()}).appendTo(this._page)},_getPosDisplayClasses:function(a){return a+"-position-"+this.options.position+" "+a+"-display-"+this.options.display},_getPanelClasses:function(){var a=this.options.classes.panel+" "+this._getPosDisplayClasses(this.options.classes.panel)+" "+this.options.classes.panelClosed;return this.options.theme&&(a+=" ui-body-"+this.options.theme),this.options.positionFixed&&(a+=" "+this.options.classes.panelFixed),a},_addPanelClasses:function(){this.element.addClass(this._getPanelClasses())},_bindCloseEvents:function(){var a=this;a._closeLink.on("click.panel",function(b){return b.preventDefault(),a.close(),!1}),a.element.on("click.panel","a:jqmData(ajax='false')",function(){a.close()})},_positionPanel:function(){var b=this,c=b._panelInner.outerHeight(),d=c>a.mobile.getScreenHeight();d||!b.options.positionFixed?(d&&(b._unfixPanel(),a.mobile.resetActivePageHeight(c)),b._scrollIntoView(c)):b._fixPanel()},_scrollIntoView:function(c){c<a(b).scrollTop()&&b.scrollTo(0,0)},_bindFixListener:function(){this._on(a(b),{throttledresize:"_positionPanel"})},_unbindFixListener:function(){this._off(a(b),"throttledresize")},_unfixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.removeClass(this.options.classes.panelFixed)},_fixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.addClass(this.options.classes.panelFixed)},_bindUpdateLayout:function(){var a=this;a.element.on("updatelayout",function(){a._open&&a._positionPanel()})},_bindLinkListeners:function(){var b=this;b._page.on("click.panel","a",function(c){if(this.hrLine truncated
|
||||
/*
|
||||
//@ sourceMappingURL=jquery.mobile-1.3.2.min.map
|
||||
*/
|
||||
@@ -1,11 +0,0 @@
|
||||
/*
|
||||
* jQuery UI Touch Punch 0.2.2
|
||||
*
|
||||
* Copyright 2011, Dave Furfero
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
* jquery.ui.mouse.js
|
||||
*/
|
||||
(function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return;}var c=b.ui.mouse.prototype,e=c._mouseInit,a;function d(g,h){if(g.originalEvent.touches.length>1){return;}g.preventDefault();var i=g.originalEvent.changedTouches[0],f=document.createEvent("MouseEvents");f.initMouseEvent(h,true,true,window,1,i.screenX,i.screenY,i.clientX,i.clientY,false,false,false,false,0,null);g.target.dispatchEvent(f);}c._touchStart=function(g){var f=this;if(a||!f._mouseCapture(g.originalEvent.changedTouches[0])){return;}a=true;f._touchMoved=false;d(g,"mouseover");d(g,"mousemove");d(g,"mousedown");};c._touchMove=function(f){if(!a){return;}this._touchMoved=true;d(f,"mousemove");};c._touchEnd=function(f){if(!a){return;}d(f,"mouseup");d(f,"mouseout");if(!this._touchMoved){d(f,"click");}a=false;};c._mouseInit=function(){var f=this;f.element.bind("touchstart",b.proxy(f,"_touchStart")).bind("touchmove",b.proxy(f,"_touchMove")).bind("touchend",b.proxy(f,"_touchEnd"));e.call(f);};})(jQuery);
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Uživatel:",
|
||||
"loginPassword": "Heslo:",
|
||||
"loginButton": "Přihlášení",
|
||||
"registerButton": "Vytvořit profil",
|
||||
"discoverReadQrButton": "Sejmout QR kód",
|
||||
"mainPageYourProfileLink": "Váš profil",
|
||||
"mainPageYourProfileLinkDesc": "Upravit profil",
|
||||
"mainPageCurrentSongLink": "Nynější píseň",
|
||||
"mainPageCurrentSongLinkDesc": "Zobrazit údaje o nynější písni",
|
||||
"mainPageSelectSong": "Všechny písně",
|
||||
"mainPageSelectSongDesc": "Vypíše všechny dostupné písně",
|
||||
"mainPageSelectPlaylist": "Všechny seznamy skladeb",
|
||||
"mainPageSelectPlaylistDesc": "Vypíše všechny seznamy skladeb",
|
||||
"mainPageSelectProfile": "Profily",
|
||||
"mainPageSelectProfileDesc": "Ukáže všechny profily",
|
||||
"mainPageTakePhotoLink": "Udělat fotografii",
|
||||
"mainPageTakePhotoLinkDesc": "Udělá fotografii a zobrazí ji na konci nynějšího kola",
|
||||
"mainPageKeyboard": "Klávesnice",
|
||||
"mainPageKeyboardDesc": "Poslat klávesy",
|
||||
"mainPageSelectUserAdmin": "Správa",
|
||||
"mainPageSelectUserAdminDesc": "Nastavit uživatelská práva",
|
||||
"mainPageLogoutLink": "Odhlásit se",
|
||||
"mainPageLogoutLinkDesc": "Zavře sezení",
|
||||
"selectProfileHeader": "Všechny profily",
|
||||
"displayProfileHeader": "Profil",
|
||||
"displayProfileName": "Jméno:",
|
||||
"displayProfilePlayerType": "Typ hráče:",
|
||||
"displayProfilePlayerTypeNormal": "Obyčejný",
|
||||
"displayProfilePlayerTypeGuest": "Host",
|
||||
"displayProfilePlayerDifficulty": "Obtížnost:",
|
||||
"displayProfilePlayerDifficultyEasy": "Snadné",
|
||||
"displayProfilePlayerDifficultyNormal": "Normální",
|
||||
"displayProfilePlayerDifficultyHard": "Těžké",
|
||||
"displayProfilePlayerPassword": "Nové heslo:",
|
||||
"displayProfilePlayerSaveButton": "Uložit a nahrát",
|
||||
"displaySongHeader": "Žádná nynější píseň",
|
||||
"displaySongArtist": "Umělec:",
|
||||
"displaySongGenre": "Žánr:",
|
||||
"displaySongYear": "Rok:",
|
||||
"displaySongLanguage": "Jazyk:",
|
||||
"displaySongIsDuet": "Duet:",
|
||||
"popupVideoClose": "Zavřít",
|
||||
"selectSongHeader": "Všechny písně",
|
||||
"keyboardHeader": "Klávesnice",
|
||||
"keyboardButtonUp": "Nahoru",
|
||||
"keyboardButtonLeft": "Vlevo",
|
||||
"keyboardButtonRight": "Vpravo",
|
||||
"keyboardButtonDown": "Dolů",
|
||||
"keyboardButtonEscape": "Esc",
|
||||
"keyboardButtonTab": "Tab",
|
||||
"keyboardButtonReturn": "Enter",
|
||||
"keyboardButtonKeys": "Pro poslání dalších kláves pište zde:",
|
||||
"selectUserAdminHeader": "Všechny profily",
|
||||
"displayUserAdminHeader": "Profil",
|
||||
"displayUserAdminContentSaveButton": "Uložit",
|
||||
"selectPlaylistHeader": "Vybrat seznam skladeb",
|
||||
"displayPlaylistHeader": "Seznam skladeb",
|
||||
"displayPlaylistSaveButton": "Uložit",
|
||||
"selectPlaylistAddPlaylistButton": "Přidat",
|
||||
"Loading (external)...": "Nahrává se (vnější)...",
|
||||
"Loading...": "Nahrává se...",
|
||||
"Creating...": "Vytváří se...",
|
||||
"Error...": "Chyba...",
|
||||
"No connection": "Žádné spojení",
|
||||
"No session": "Žádné sezení",
|
||||
"Uploading photo...": "Nahrává se fotografie...",
|
||||
"Getting current song...": "Získává se nynější píseň...",
|
||||
"Login...": "Přihlašuje se...",
|
||||
"Creating profile...": "Vytváří se profil...",
|
||||
"This is not a valid name.": "Toto není platný název.",
|
||||
"Uploading profile...": "Nahrává se profil...",
|
||||
"songs": "Písně",
|
||||
"YourName": "Vaše jméno",
|
||||
"discoverConnectHeader": "Připojit se k serveru",
|
||||
"discoverConnectServerAddress": "Adresa serveru:",
|
||||
"discoverConnectButton": "Připojit se",
|
||||
"Checking...": "Ověřuje se...",
|
||||
"timeout": "Překročení časového omezení",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Ctrl",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Poslat klávesy automaticky",
|
||||
"keyboardButtonSend": "Poslat"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Benutzer:",
|
||||
"loginPassword": "Passwort:",
|
||||
"loginButton": "Einloggen",
|
||||
"registerButton": "Erstelle Profil",
|
||||
"discoverReadQrButton": "Scanne QR Code",
|
||||
"mainPageYourProfileLink": "Dein Profil",
|
||||
"mainPageYourProfileLinkDesc": "Bearbeite dein Profil",
|
||||
"mainPageCurrentSongLink": "Aktuelles Lied",
|
||||
"mainPageCurrentSongLinkDesc": "Zeigt Informationen über das aktuelle Lied an",
|
||||
"mainPageSelectSong": "Alle Lieder",
|
||||
"mainPageSelectSongDesc": "Listet alle verfügbaren Lieder auf",
|
||||
"mainPageSelectPlaylist": "Alle Playlisten",
|
||||
"mainPageSelectPlaylistDesc": "Listet alle verfügbaren Playlisten auf",
|
||||
"mainPageSelectProfile": "Profile",
|
||||
"mainPageSelectProfileDesc": "Listet alle Profile auf",
|
||||
"mainPageTakePhotoLink": "Foto aufnehmen",
|
||||
"mainPageTakePhotoLinkDesc": "Nimmt ein Foto auf und zeigt es am Ende der Runde an",
|
||||
"mainPageKeyboard": "Tastatur",
|
||||
"mainPageKeyboardDesc": "Sende Tastatureingaben",
|
||||
"mainPageSelectUserAdmin": "Administration",
|
||||
"mainPageSelectUserAdminDesc": "Konfiguriere die Benutzerrechte",
|
||||
"mainPageLogoutLink": "Abmelden",
|
||||
"mainPageLogoutLinkDesc": "Beendet diese Sitzung",
|
||||
"selectProfileHeader": "Alle Profile",
|
||||
"displayProfileHeader": "Profile",
|
||||
"displayProfileName": "Name:",
|
||||
"displayProfilePlayerType": "Spielertyp:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Gast",
|
||||
"displayProfilePlayerDifficulty": "Schwierigkeit:",
|
||||
"displayProfilePlayerDifficultyEasy": "Einfach",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Schwer",
|
||||
"displayProfilePlayerPassword": "Neues Passwort:",
|
||||
"displayProfilePlayerSaveButton": "Speichern und hochladen",
|
||||
"displaySongHeader": "Kein aktuelles Lied",
|
||||
"displaySongArtist": "Künstler:",
|
||||
"displaySongGenre": "Genre:",
|
||||
"displaySongYear": "Jahr:",
|
||||
"displaySongLanguage": "Sprache:",
|
||||
"displaySongIsDuet": "Duet:",
|
||||
"popupVideoClose": "Schließen",
|
||||
"selectSongHeader": "Alle Lieder",
|
||||
"keyboardHeader": "Tastatur",
|
||||
"keyboardButtonUp": "hoch",
|
||||
"keyboardButtonLeft": "links",
|
||||
"keyboardButtonRight": "rechts",
|
||||
"keyboardButtonDown": "runter",
|
||||
"keyboardButtonEscape": "Escape",
|
||||
"keyboardButtonTab": "Tab",
|
||||
"keyboardButtonReturn": "Enter",
|
||||
"keyboardButtonKeys": "Um andere Zeichen zu senden, hier tippen:",
|
||||
"selectUserAdminHeader": "Alle Profile",
|
||||
"displayUserAdminHeader": "Profile",
|
||||
"displayUserAdminContentSaveButton": "Speichern",
|
||||
"selectPlaylistHeader": "Wähle eine Playlist",
|
||||
"displayPlaylistHeader": "Playlist",
|
||||
"displayPlaylistSaveButton": "Speichern",
|
||||
"selectPlaylistAddPlaylistButton": "Hinzufügen",
|
||||
"Loading (external)...": "Laden (extern)...",
|
||||
"Loading...": "Laden...",
|
||||
"Creating...": "Erstellen...",
|
||||
"Error...": "Fehler...",
|
||||
"No connection": "Keine Verbindung",
|
||||
"No session": "Keine Sitzung",
|
||||
"Uploading photo...": "Foto hochladen...",
|
||||
"Getting current song...": "Lade aktuelles Lied...",
|
||||
"Login...": "Einloggen...",
|
||||
"Creating profile...": "Erstelle Profil...",
|
||||
"This is not a valid name.": "Dies ist kein gültiger Name.",
|
||||
"Uploading profile...": "Profil hochladen...",
|
||||
"songs": "Lieder",
|
||||
"YourName": "DeinName",
|
||||
"discoverConnectHeader": "Verbinde zum Server",
|
||||
"discoverConnectServerAddress": "Serveradresse:",
|
||||
"discoverConnectButton": "Verbinden",
|
||||
"Checking...": "Prüfen...",
|
||||
"timeout": "Zeitüberschreitung",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Steuerung",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Automatisch Tasten senden",
|
||||
"keyboardButtonSend": "Senden"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "User:",
|
||||
"loginPassword": "Password:",
|
||||
"loginButton": "Login",
|
||||
"registerButton": "Create Profile",
|
||||
"discoverReadQrButton": "Scan QRCode",
|
||||
"mainPageYourProfileLink": "Your Profile",
|
||||
"mainPageYourProfileLinkDesc": "Edit your profile",
|
||||
"mainPageCurrentSongLink": "Current Song",
|
||||
"mainPageCurrentSongLinkDesc": "Display informations about the current song",
|
||||
"mainPageSelectSong": "All songs",
|
||||
"mainPageSelectSongDesc": "Lists all available songs",
|
||||
"mainPageSelectPlaylist": "All playlists",
|
||||
"mainPageSelectPlaylistDesc": "Lists all playlists",
|
||||
"mainPageSelectProfile": "Profiles",
|
||||
"mainPageSelectProfileDesc": "Shows all profiles",
|
||||
"mainPageTakePhotoLink": "Take Photo",
|
||||
"mainPageTakePhotoLinkDesc": "Takes a photo and displays it at the end of the current round",
|
||||
"mainPageKeyboard": "Keyboard",
|
||||
"mainPageKeyboardDesc": "Send keys",
|
||||
"mainPageSelectUserAdmin": "Administration",
|
||||
"mainPageSelectUserAdminDesc": "Configure user rights",
|
||||
"mainPageLogoutLink": "Logout",
|
||||
"mainPageLogoutLinkDesc": "Closes the session",
|
||||
"selectProfileHeader": "All profiles",
|
||||
"displayProfileHeader": "Profile",
|
||||
"displayProfileName": "Name:",
|
||||
"displayProfilePlayerType": "Player Type:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Guest",
|
||||
"displayProfilePlayerDifficulty": "Difficulty:",
|
||||
"displayProfilePlayerDifficultyEasy": "Easy",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Hard",
|
||||
"displayProfilePlayerPassword": "New Password:",
|
||||
"displayProfilePlayerSaveButton": "Save and upload",
|
||||
"displaySongHeader": "No current song",
|
||||
"displaySongArtist": "Artist:",
|
||||
"displaySongGenre": "Genre:",
|
||||
"displaySongYear": "Year:",
|
||||
"displaySongLanguage": "Language:",
|
||||
"displaySongIsDuet": "Duet:",
|
||||
"popupVideoClose": "Close",
|
||||
"selectSongHeader": "All songs",
|
||||
"keyboardHeader": "Keyboard",
|
||||
"keyboardButtonUp": "up",
|
||||
"keyboardButtonLeft": "left",
|
||||
"keyboardButtonRight": "right",
|
||||
"keyboardButtonDown": "down",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "return",
|
||||
"keyboardButtonKeys": "To send other keys type here:",
|
||||
"selectUserAdminHeader": "All profiles",
|
||||
"displayUserAdminHeader": "Profile",
|
||||
"displayUserAdminContentSaveButton": "Save",
|
||||
"selectPlaylistHeader": "Select a playlist",
|
||||
"displayPlaylistHeader": "Playlist",
|
||||
"displayPlaylistSaveButton": "Save",
|
||||
"selectPlaylistAddPlaylistButton": "Add",
|
||||
"Loading (external)...": "Loading (external)...",
|
||||
"Loading...": "Loading...",
|
||||
"Creating...": "Creating...",
|
||||
"Error...": "Error...",
|
||||
"No connection": "No connection",
|
||||
"No session": "No session",
|
||||
"Uploading photo...": "Uploading photo...",
|
||||
"Getting current song...": "Getting current song...",
|
||||
"Login...": "Login...",
|
||||
"Creating profile...": "Creating profile...",
|
||||
"This is not a valid name.": "This is not a valid name.",
|
||||
"Uploading profile...": "Uploading profile...",
|
||||
"songs": "songs",
|
||||
"YourName": "YourName",
|
||||
"discoverConnectHeader": "Connect to server",
|
||||
"discoverConnectServerAddress": "Serveraddress:",
|
||||
"discoverConnectButton": "Connect",
|
||||
"Checking...": "Checking...",
|
||||
"timeout": "Timeout",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Auto send keys",
|
||||
"keyboardButtonSend": "Send"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Usuario:",
|
||||
"loginPassword": "Contraseña:",
|
||||
"loginButton": "Iniciar sesión",
|
||||
"registerButton": "Crear perfil",
|
||||
"discoverReadQrButton": "Escanear código QR",
|
||||
"mainPageYourProfileLink": "Tu perfil",
|
||||
"mainPageYourProfileLinkDesc": "Editar tu perfil",
|
||||
"mainPageCurrentSongLink": "Canción actual",
|
||||
"mainPageCurrentSongLinkDesc": "Mostrar información sobre la canción actual",
|
||||
"mainPageSelectSong": "Todas las canciones",
|
||||
"mainPageSelectSongDesc": "Lista de las canciones disponibles",
|
||||
"mainPageSelectPlaylist": "Todas las listas de reproducción",
|
||||
"mainPageSelectPlaylistDesc": "Lista de todas las listas de reproducción",
|
||||
"mainPageSelectProfile": "Pefiles",
|
||||
"mainPageSelectProfileDesc": "Mostrar todos los perfiles",
|
||||
"mainPageTakePhotoLink": "Hacer foto",
|
||||
"mainPageTakePhotoLinkDesc": "Hacer una foto y mostrarla al final de la ronda actual",
|
||||
"mainPageKeyboard": "Teclado",
|
||||
"mainPageKeyboardDesc": "Enviar teclas",
|
||||
"mainPageSelectUserAdmin": "Administración",
|
||||
"mainPageSelectUserAdminDesc": "Configurar derechos de usuario",
|
||||
"mainPageLogoutLink": "Cerrar sesión",
|
||||
"mainPageLogoutLinkDesc": "Cerrar la sesión",
|
||||
"selectProfileHeader": "Todos los perfiles",
|
||||
"displayProfileHeader": "Perfil",
|
||||
"displayProfileName": "Nombre:",
|
||||
"displayProfilePlayerType": "Tipo de usuario:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Invitado",
|
||||
"displayProfilePlayerDifficulty": "Dificultad:",
|
||||
"displayProfilePlayerDifficultyEasy": "Fácil",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Difícil",
|
||||
"displayProfilePlayerPassword": "Nueva contraseña:",
|
||||
"displayProfilePlayerSaveButton": "Guardar y subir",
|
||||
"displaySongHeader": "Ninguna canción ahora",
|
||||
"displaySongArtist": "Artista:",
|
||||
"displaySongGenre": "Género:",
|
||||
"displaySongYear": "Año:",
|
||||
"displaySongLanguage": "Idioma:",
|
||||
"displaySongIsDuet": "Dueto:",
|
||||
"popupVideoClose": "Cerrar",
|
||||
"selectSongHeader": "Todas las canciones",
|
||||
"keyboardHeader": "Teclado",
|
||||
"keyboardButtonUp": "arriba",
|
||||
"keyboardButtonLeft": "izquierda",
|
||||
"keyboardButtonRight": "derecha",
|
||||
"keyboardButtonDown": "abajo",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tabulación",
|
||||
"keyboardButtonReturn": "intro",
|
||||
"keyboardButtonKeys": "Para enviar otras teclas escribe aquí:",
|
||||
"selectUserAdminHeader": "Todos los perfiles",
|
||||
"displayUserAdminHeader": "Perfil",
|
||||
"displayUserAdminContentSaveButton": "Guardar",
|
||||
"selectPlaylistHeader": "Seleccionar una lista de reproducción",
|
||||
"displayPlaylistHeader": "Lista de reproducción",
|
||||
"displayPlaylistSaveButton": "Guardar",
|
||||
"selectPlaylistAddPlaylistButton": "Añadir",
|
||||
"Loading (external)...": "Cargando (externo)...",
|
||||
"Loading...": "Cargando...",
|
||||
"Creating...": "Creando...",
|
||||
"Error...": "Error...",
|
||||
"No connection": "Sin conexión",
|
||||
"No session": "Sin sesión",
|
||||
"Uploading photo...": "Subiendo foto...",
|
||||
"Getting current song...": "Obteniendo la canción actual...",
|
||||
"Login...": "Iniciando sesión...",
|
||||
"Creating profile...": "Creando pefil...",
|
||||
"This is not a valid name.": "Este no es un nombre válido.",
|
||||
"Uploading profile...": "Subiendo perfil...",
|
||||
"songs": "canciones",
|
||||
"YourName": "Tu nombre",
|
||||
"discoverConnectHeader": "Conectar al servidor",
|
||||
"discoverConnectServerAddress": "Dirección del servidor:",
|
||||
"discoverConnectButton": "Conectar",
|
||||
"Checking...": "Comprobando...",
|
||||
"timeout": "Tiempo de espera",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Retroceso",
|
||||
"keyboardAutoSend": "Auto-enviar teclas.",
|
||||
"keyboardButtonSend": "Mandar"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Käyttäjä:",
|
||||
"loginPassword": "Salasana:",
|
||||
"loginButton": "Kirjaudu",
|
||||
"registerButton": "Luo Profiili",
|
||||
"discoverReadQrButton": "Skannaa QR-koodi",
|
||||
"mainPageYourProfileLink": "Oma Profiili",
|
||||
"mainPageYourProfileLinkDesc": "Muokkaa profiilia",
|
||||
"mainPageCurrentSongLink": "Laulettavana",
|
||||
"mainPageCurrentSongLinkDesc": "Näytä tietoa laulusta",
|
||||
"mainPageSelectSong": "Kaikki laulut",
|
||||
"mainPageSelectSongDesc": "Näytä kaikki laulut",
|
||||
"mainPageSelectPlaylist": "Kaikki soittolistat",
|
||||
"mainPageSelectPlaylistDesc": "Näytä kaikki soittolistat",
|
||||
"mainPageSelectProfile": "Profiilit",
|
||||
"mainPageSelectProfileDesc": "Näyttää kaikki profiilit",
|
||||
"mainPageTakePhotoLink": "Ota Kuva",
|
||||
"mainPageTakePhotoLinkDesc": "Ottaa kuvan ja näyttää sen kierroksen lopussa",
|
||||
"mainPageKeyboard": "Näppäimistö",
|
||||
"mainPageKeyboardDesc": "Lähettää näppäinpainelluksia",
|
||||
"mainPageSelectUserAdmin": "Ylläpito",
|
||||
"mainPageSelectUserAdminDesc": "Säädä käyttöoikeuksia",
|
||||
"mainPageLogoutLink": "Kirjaudu ulos",
|
||||
"mainPageLogoutLinkDesc": "Lopettaa istunnon",
|
||||
"selectProfileHeader": "Kaikki profiilit",
|
||||
"displayProfileHeader": "Profiili",
|
||||
"displayProfileName": "Nimi:",
|
||||
"displayProfilePlayerType": "Pelaajatyyppi:",
|
||||
"displayProfilePlayerTypeNormal": "Normaali",
|
||||
"displayProfilePlayerTypeGuest": "Vieras",
|
||||
"displayProfilePlayerDifficulty": "Vaikeustaso:",
|
||||
"displayProfilePlayerDifficultyEasy": "Helppo",
|
||||
"displayProfilePlayerDifficultyNormal": "Normaali",
|
||||
"displayProfilePlayerDifficultyHard": "Vaikea",
|
||||
"displayProfilePlayerPassword": "Uusi Salasana",
|
||||
"displayProfilePlayerSaveButton": "Tallenna ja lähetä",
|
||||
"displaySongHeader": "Ei valittua laulua",
|
||||
"displaySongArtist": "Artisti:",
|
||||
"displaySongGenre": "Genre:",
|
||||
"displaySongYear": "Vuosi:",
|
||||
"displaySongLanguage": "Kieli:",
|
||||
"displaySongIsDuet": "Duetto:",
|
||||
"popupVideoClose": "Sulje",
|
||||
"selectSongHeader": "Kaikki laulut",
|
||||
"keyboardHeader": "Näppäimistö",
|
||||
"keyboardButtonUp": "ylös",
|
||||
"keyboardButtonLeft": "vasen",
|
||||
"keyboardButtonRight": "oikea",
|
||||
"keyboardButtonDown": "alas",
|
||||
"keyboardButtonEscape": "esc-näppäin",
|
||||
"keyboardButtonTab": "sarkain",
|
||||
"keyboardButtonReturn": "rivinvaihto",
|
||||
"keyboardButtonKeys": "Lähetä muita painalluksia kirjoittamalla tähän:",
|
||||
"selectUserAdminHeader": "Kaikki profiilit",
|
||||
"displayUserAdminHeader": "Profiili",
|
||||
"displayUserAdminContentSaveButton": "Tallenna",
|
||||
"selectPlaylistHeader": "Valitse soittolista",
|
||||
"displayPlaylistHeader": "Soittolista",
|
||||
"displayPlaylistSaveButton": "Tallenna",
|
||||
"selectPlaylistAddPlaylistButton": "Lisää",
|
||||
"Loading (external)...": "Ladataan (ulkoinen)...",
|
||||
"Loading...": "Ladataan...",
|
||||
"Creating...": "Luodaan...",
|
||||
"Error...": "Virhe...",
|
||||
"No connection": "Ei yhteyttä",
|
||||
"No session": "Ei istuntoa",
|
||||
"Uploading photo...": "Lähetetään kuvaa...",
|
||||
"Getting current song...": "Haetaan laulua...",
|
||||
"Login...": "Kirjaudutaan...",
|
||||
"Creating profile...": "Luodaan profiilia...",
|
||||
"This is not a valid name.": "Nimi ei ole sopiva.",
|
||||
"Uploading profile...": "Lähetetään profiilia...",
|
||||
"songs": "laulut",
|
||||
"YourName": "SinunNimesi",
|
||||
"discoverConnectHeader": "Yhdistä palvelimeen",
|
||||
"discoverConnectServerAddress": "Palvelinosoite:",
|
||||
"discoverConnectButton": "Yhdistä",
|
||||
"Checking...": "Tarkistetaan...",
|
||||
"timeout": "Aikakatkaisu",
|
||||
"keyboardButtonShift": "Siirto",
|
||||
"keyboardButtonAlt": "Vaihto",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Askelpalautin",
|
||||
"keyboardAutoSend": "Lähetä näppäimet autom.",
|
||||
"keyboardButtonSend": "Lähetä"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Utilisateur :",
|
||||
"loginPassword": "Mot de passe :",
|
||||
"loginButton": "Login",
|
||||
"registerButton": "Créer un profil",
|
||||
"discoverReadQrButton": "Scanner un QRCode",
|
||||
"mainPageYourProfileLink": "Votre profil",
|
||||
"mainPageYourProfileLinkDesc": "Editer votre profil",
|
||||
"mainPageCurrentSongLink": "Chanson actuelle",
|
||||
"mainPageCurrentSongLinkDesc": "Afficher les informations à propos de la chanson actuelle",
|
||||
"mainPageSelectSong": "Toutes les chansons",
|
||||
"mainPageSelectSongDesc": "Lister toutes les chansons disponible",
|
||||
"mainPageSelectPlaylist": "Toutes les playlists",
|
||||
"mainPageSelectPlaylistDesc": "Lister toutes les playlists",
|
||||
"mainPageSelectProfile": "Profils",
|
||||
"mainPageSelectProfileDesc": "Afficher tous les profils",
|
||||
"mainPageTakePhotoLink": "Prendre une photo",
|
||||
"mainPageTakePhotoLinkDesc": "Prends une photo et l'affiche à la fin de la partie actuelle",
|
||||
"mainPageKeyboard": "Clavier",
|
||||
"mainPageKeyboardDesc": "Envoyer les caractères",
|
||||
"mainPageSelectUserAdmin": "Administration",
|
||||
"mainPageSelectUserAdminDesc": "Configurer les droits administrateurs",
|
||||
"mainPageLogoutLink": "Se déconnecter",
|
||||
"mainPageLogoutLinkDesc": "Fermer la session",
|
||||
"selectProfileHeader": "Tous les profils",
|
||||
"displayProfileHeader": "Profil",
|
||||
"displayProfileName": "Nom :",
|
||||
"displayProfilePlayerType": "Type de joueur :",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Invité",
|
||||
"displayProfilePlayerDifficulty": "Dificulté :",
|
||||
"displayProfilePlayerDifficultyEasy": "Facile",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Difficile",
|
||||
"displayProfilePlayerPassword": "Nouveau mot de passe :",
|
||||
"displayProfilePlayerSaveButton": "Sauvegarder et télécharger",
|
||||
"displaySongHeader": "Pas de chanson actuelle",
|
||||
"displaySongArtist": "Artiste :",
|
||||
"displaySongGenre": "Genre :",
|
||||
"displaySongYear": "Année :",
|
||||
"displaySongLanguage": "Langue :",
|
||||
"displaySongIsDuet": "Duo :",
|
||||
"popupVideoClose": "Fermer",
|
||||
"selectSongHeader": "Toutes les chansons",
|
||||
"keyboardHeader": "Clavier",
|
||||
"keyboardButtonUp": "haut",
|
||||
"keyboardButtonLeft": "gauche",
|
||||
"keyboardButtonRight": "droite",
|
||||
"keyboardButtonDown": "bas",
|
||||
"keyboardButtonEscape": "echappe",
|
||||
"keyboardButtonTab": "tabulation",
|
||||
"keyboardButtonReturn": "Retour",
|
||||
"keyboardButtonKeys": "Pour envoyer d'autres caractères, taper ici :",
|
||||
"selectUserAdminHeader": "Tous les profils",
|
||||
"displayUserAdminHeader": "Profil",
|
||||
"displayUserAdminContentSaveButton": "Sauvegarder",
|
||||
"selectPlaylistHeader": "Sélectionner une playlist",
|
||||
"displayPlaylistHeader": "Playlist",
|
||||
"displayPlaylistSaveButton": "Sauvegarder",
|
||||
"selectPlaylistAddPlaylistButton": "Ajouter",
|
||||
"Loading (external)...": "Chargement (externe)...",
|
||||
"Loading...": "Chargement...",
|
||||
"Creating...": "Création...",
|
||||
"Error...": "Erreur...",
|
||||
"No connection": "Pas de connexion",
|
||||
"No session": "Pas de session",
|
||||
"Uploading photo...": "Téléchargement de la photo...",
|
||||
"Getting current song...": "Récupération de la chanson actuelle...",
|
||||
"Login...": "Connexion...",
|
||||
"Creating profile...": "Création du profil...",
|
||||
"This is not a valid name.": "Le nom n'est pas valide.",
|
||||
"Uploading profile...": "Téléchargement du profil...",
|
||||
"songs": "Chansons",
|
||||
"YourName": "VotreNom",
|
||||
"discoverConnectHeader": "Se connecter au serveur",
|
||||
"discoverConnectServerAddress": "Adresse du serveur :",
|
||||
"discoverConnectButton": "Connecter",
|
||||
"Checking...": "Vérification",
|
||||
"timeout": "Temps dépassé",
|
||||
"keyboardButtonShift": "Maj.",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Controle",
|
||||
"keyboardButtonBackspace": "Retour",
|
||||
"keyboardAutoSend": "Envoyer la saisie automatiquement",
|
||||
"keyboardButtonSend": "Envoyer"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Név:",
|
||||
"loginPassword": "Jelszó:",
|
||||
"loginButton": "Bejelentkezés",
|
||||
"registerButton": "Új Profil",
|
||||
"discoverReadQrButton": "QR-kód beolvasása",
|
||||
"mainPageYourProfileLink": "Saját Profil",
|
||||
"mainPageYourProfileLinkDesc": "Saját profil szerkesztése",
|
||||
"mainPageCurrentSongLink": "Jelenlegi dal",
|
||||
"mainPageCurrentSongLinkDesc": "Információk mutatása a jelenlegi dalról",
|
||||
"mainPageSelectSong": "Minden dal",
|
||||
"mainPageSelectSongDesc": "Minden elérhető dal listázása",
|
||||
"mainPageSelectPlaylist": "Minden lejátszási lista",
|
||||
"mainPageSelectPlaylistDesc": "Minden lejátszási lista mutatása",
|
||||
"mainPageSelectProfile": "Profilok",
|
||||
"mainPageSelectProfileDesc": "Minden profil mutatása",
|
||||
"mainPageTakePhotoLink": "Fénykép készítése",
|
||||
"mainPageTakePhotoLinkDesc": "Fényképet készít és megmutatja a kör végén",
|
||||
"mainPageKeyboard": "Billentyűzet",
|
||||
"mainPageKeyboardDesc": "Billentyűzet kezelése",
|
||||
"mainPageSelectUserAdmin": "Adminisztráció",
|
||||
"mainPageSelectUserAdminDesc": "Felhasználói jogok beállítása",
|
||||
"mainPageLogoutLink": "Kijelentkezés",
|
||||
"mainPageLogoutLinkDesc": "Másik profilra váltáshoz",
|
||||
"selectProfileHeader": "Minden profil",
|
||||
"displayProfileHeader": "Profil",
|
||||
"displayProfileName": "Név:",
|
||||
"displayProfilePlayerType": "Játékos Típusa",
|
||||
"displayProfilePlayerTypeNormal": "Normál",
|
||||
"displayProfilePlayerTypeGuest": "Vendég",
|
||||
"displayProfilePlayerDifficulty": "Nehézségi szint",
|
||||
"displayProfilePlayerDifficultyEasy": "Könnyű",
|
||||
"displayProfilePlayerDifficultyNormal": "Normál",
|
||||
"displayProfilePlayerDifficultyHard": "Nehéz",
|
||||
"displayProfilePlayerPassword": "Új Jelszó:",
|
||||
"displayProfilePlayerSaveButton": "Mentés",
|
||||
"displaySongHeader": "Jelenlegi dal",
|
||||
"displaySongArtist": "Előadó:",
|
||||
"displaySongGenre": "Műfaj:",
|
||||
"displaySongYear": "Év:",
|
||||
"displaySongLanguage": "Nyelv:",
|
||||
"displaySongIsDuet": "Duett:",
|
||||
"popupVideoClose": "Bezárás",
|
||||
"selectSongHeader": "Minden Dal",
|
||||
"keyboardHeader": "Billentyűzet",
|
||||
"keyboardButtonUp": "fel",
|
||||
"keyboardButtonLeft": "balra",
|
||||
"keyboardButtonRight": "jobbra",
|
||||
"keyboardButtonDown": "le",
|
||||
"keyboardButtonEscape": "esc",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "enter",
|
||||
"keyboardButtonKeys": "Egyéb billentyűk küldéséhez írd ide:",
|
||||
"selectUserAdminHeader": "Minden profil",
|
||||
"displayUserAdminHeader": "Profil",
|
||||
"displayUserAdminContentSaveButton": "Mentés",
|
||||
"selectPlaylistHeader": "Lejátszási lista kiválasztása",
|
||||
"displayPlaylistHeader": "Lejátszási lista",
|
||||
"displayPlaylistSaveButton": "Mentés",
|
||||
"selectPlaylistAddPlaylistButton": "Hozzáadás",
|
||||
"Loading (external)...": "Betöltés (külső)...",
|
||||
"Loading...": "Betöltés...",
|
||||
"Creating...": "Elkészítés...",
|
||||
"Error...": "Hiba...",
|
||||
"No connection": "Nincs kapcsolat",
|
||||
"No session": "Nincs kapcsolódás",
|
||||
"Uploading photo...": "Fénykép feltöltése...",
|
||||
"Getting current song...": "Jelenlegi dal betöltése...",
|
||||
"Login...": "Bejelentkezés...",
|
||||
"Creating profile...": "Profil létrehozása...",
|
||||
"This is not a valid name.": "Érvénytelen név.",
|
||||
"Uploading profile...": "Profil feltöltése...",
|
||||
"songs": "dalok",
|
||||
"YourName": "IdeÍrdANeved",
|
||||
"discoverConnectHeader": "Kapcsolódás a szerverhez",
|
||||
"discoverConnectServerAddress": "Szerver címe:",
|
||||
"discoverConnectButton": "Kapcsolódás",
|
||||
"Checking...": "Ellenőrzés...",
|
||||
"timeout": "Időtúllépés",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Ctrl",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Billentyűleütések automatikus küldése",
|
||||
"keyboardButtonSend": "Küldés"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Utente:",
|
||||
"loginPassword": "Password:",
|
||||
"loginButton": "Entra",
|
||||
"registerButton": "Crea profilo",
|
||||
"discoverReadQrButton": "Scansione codice QR",
|
||||
"mainPageYourProfileLink": "Tuo profilo",
|
||||
"mainPageYourProfileLinkDesc": "Modifica il tuo profilo",
|
||||
"mainPageCurrentSongLink": "Canzone corrente",
|
||||
"mainPageCurrentSongLinkDesc": "Visualizza informazioni sulla canzone corrente",
|
||||
"mainPageSelectSong": "Tutte le canzoni",
|
||||
"mainPageSelectSongDesc": "Elenca tutte le canzoni disponibili",
|
||||
"mainPageSelectPlaylist": "Tutte le playlist",
|
||||
"mainPageSelectPlaylistDesc": "Elenca tutte le playlist",
|
||||
"mainPageSelectProfile": "Profili",
|
||||
"mainPageSelectProfileDesc": "Mostra tutti i profili",
|
||||
"mainPageTakePhotoLink": "Scatta una foto",
|
||||
"mainPageTakePhotoLinkDesc": "Scatta una foto e visualizzala alla fine del turno corrente",
|
||||
"mainPageKeyboard": "Tastiera",
|
||||
"mainPageKeyboardDesc": "Invio tasti",
|
||||
"mainPageSelectUserAdmin": "Amministrazione",
|
||||
"mainPageSelectUserAdminDesc": "Configura diritti utente",
|
||||
"mainPageLogoutLink": "Esci",
|
||||
"mainPageLogoutLinkDesc": "Chiudi la sessione",
|
||||
"selectProfileHeader": "Tutti i profili",
|
||||
"displayProfileHeader": "Profilo",
|
||||
"displayProfileName": "Nome:",
|
||||
"displayProfilePlayerType": "Tipo giocatore:",
|
||||
"displayProfilePlayerTypeNormal": "Normale",
|
||||
"displayProfilePlayerTypeGuest": "Ospite",
|
||||
"displayProfilePlayerDifficulty": "Difficoltà:",
|
||||
"displayProfilePlayerDifficultyEasy": "Facile",
|
||||
"displayProfilePlayerDifficultyNormal": "Normale",
|
||||
"displayProfilePlayerDifficultyHard": "Difficile",
|
||||
"displayProfilePlayerPassword": "Nuova password:",
|
||||
"displayProfilePlayerSaveButton": "Salva e carica",
|
||||
"displaySongHeader": "Nessuna canzone corrente",
|
||||
"displaySongArtist": "Artista:",
|
||||
"displaySongGenre": "Genere:",
|
||||
"displaySongYear": "Anno:",
|
||||
"displaySongLanguage": "Lingua:",
|
||||
"displaySongIsDuet": "Duetto:",
|
||||
"popupVideoClose": "Chiudi",
|
||||
"selectSongHeader": "Tutte le canzoni",
|
||||
"keyboardHeader": "Tastiera",
|
||||
"keyboardButtonUp": "su",
|
||||
"keyboardButtonLeft": "sinistra",
|
||||
"keyboardButtonRight": "destra",
|
||||
"keyboardButtonDown": "giu",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "invio",
|
||||
"keyboardButtonKeys": "Per inviare altri tasti scrivi qui:",
|
||||
"selectUserAdminHeader": "Tutti i profili",
|
||||
"displayUserAdminHeader": "Profilo",
|
||||
"displayUserAdminContentSaveButton": "Salva",
|
||||
"selectPlaylistHeader": "Seleziona una playlist",
|
||||
"displayPlaylistHeader": "Playlist",
|
||||
"displayPlaylistSaveButton": "Salva",
|
||||
"selectPlaylistAddPlaylistButton": "Aggiungi",
|
||||
"Loading (external)...": "Caricamento(esterno)...",
|
||||
"Loading...": "Caricamento...",
|
||||
"Creating...": "Creazione...",
|
||||
"Error...": "Errore...",
|
||||
"No connection": "Nessuna connessione",
|
||||
"No session": "Nessuna sessione",
|
||||
"Uploading photo...": "Caricamento foto...",
|
||||
"Getting current song...": "Recupero canzone corrente...",
|
||||
"Login...": "Login...",
|
||||
"Creating profile...": "Creazione profilo...",
|
||||
"This is not a valid name.": "Questo nome non è valido.",
|
||||
"Uploading profile...": "Caricamento profilo...",
|
||||
"songs": "canzoni",
|
||||
"YourName": "Tuo nome",
|
||||
"discoverConnectHeader": "Connetti al server",
|
||||
"discoverConnectServerAddress": "Indirizzo server:",
|
||||
"discoverConnectButton": "Connetti",
|
||||
"Checking...": "Controllo...",
|
||||
"timeout": "Timeout",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Tasti auto invio",
|
||||
"keyboardButtonSend": "Invia"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Gebruiker:",
|
||||
"loginPassword": "Wachtwoord:",
|
||||
"loginButton": "Login",
|
||||
"registerButton": "Creëer profiel",
|
||||
"discoverReadQrButton": "Scan QR Code",
|
||||
"mainPageYourProfileLink": "Je profiel",
|
||||
"mainPageYourProfileLinkDesc": "Wijzig je profiel",
|
||||
"mainPageCurrentSongLink": "Huidig liedje",
|
||||
"mainPageCurrentSongLinkDesc": "Geef informatie weer over het huidige liedje",
|
||||
"mainPageSelectSong": "Alle liedjes",
|
||||
"mainPageSelectSongDesc": "Toon alle beschikbare liedjes",
|
||||
"mainPageSelectPlaylist": "Alle afspeellijsten",
|
||||
"mainPageSelectPlaylistDesc": "Toon alle afspeellijsten",
|
||||
"mainPageSelectProfile": "Profielen",
|
||||
"mainPageSelectProfileDesc": "Toon alle profielen",
|
||||
"mainPageTakePhotoLink": "Maak een foto",
|
||||
"mainPageTakePhotoLinkDesc": "Maak een foto en toon deze aan het einde van de huidige ronde",
|
||||
"mainPageKeyboard": "Toetsenbord",
|
||||
"mainPageKeyboardDesc": "Zend toetsen",
|
||||
"mainPageSelectUserAdmin": "Administratie",
|
||||
"mainPageSelectUserAdminDesc": "Wijzig gebruikersrechten",
|
||||
"mainPageLogoutLink": "Log uit",
|
||||
"mainPageLogoutLinkDesc": "Sluit de sessie",
|
||||
"selectProfileHeader": "Alle profielen",
|
||||
"displayProfileHeader": "Profiel",
|
||||
"displayProfileName": "Naam:",
|
||||
"displayProfilePlayerType": "Speler soort:",
|
||||
"displayProfilePlayerTypeNormal": "Normaal",
|
||||
"displayProfilePlayerTypeGuest": "Gast",
|
||||
"displayProfilePlayerDifficulty": "Moeilijkheidsgraad:",
|
||||
"displayProfilePlayerDifficultyEasy": "Makkelijk",
|
||||
"displayProfilePlayerDifficultyNormal": "Normaal",
|
||||
"displayProfilePlayerDifficultyHard": "Moeilijk",
|
||||
"displayProfilePlayerPassword": "Nieuw wachtwoord:",
|
||||
"displayProfilePlayerSaveButton": "Opslaan en opsturen",
|
||||
"displaySongHeader": "Geen huidig liedje",
|
||||
"displaySongArtist": "Artiest:",
|
||||
"displaySongGenre": "Genre:",
|
||||
"displaySongYear": "Jaar:",
|
||||
"displaySongLanguage": "Taal:",
|
||||
"displaySongIsDuet": "Duet:",
|
||||
"popupVideoClose": "Sluiten",
|
||||
"selectSongHeader": "Alle liedjes",
|
||||
"keyboardHeader": "Toetsenbord",
|
||||
"keyboardButtonUp": "omhoog",
|
||||
"keyboardButtonLeft": "links",
|
||||
"keyboardButtonRight": "rechts",
|
||||
"keyboardButtonDown": "omlaag",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "enter",
|
||||
"keyboardButtonKeys": "Om andere toetsen te versturen, typ hier:",
|
||||
"selectUserAdminHeader": "Alle profielen",
|
||||
"displayUserAdminHeader": "Profiel",
|
||||
"displayUserAdminContentSaveButton": "Opslaan",
|
||||
"selectPlaylistHeader": "Selecteer een afspeellijst",
|
||||
"displayPlaylistHeader": "Afspeellijst",
|
||||
"displayPlaylistSaveButton": "Opslaan",
|
||||
"selectPlaylistAddPlaylistButton": "Toevoegen",
|
||||
"Loading (external)...": "Laden (extern)...",
|
||||
"Loading...": "Laden...",
|
||||
"Creating...": "Creeeren...",
|
||||
"Error...": "Fout...",
|
||||
"No connection": "Geen verbinding",
|
||||
"No session": "Geen sessie",
|
||||
"Uploading photo...": "Foto uploaden...",
|
||||
"Getting current song...": "Ophalen van huidig liedje...",
|
||||
"Login...": "Inloggen...",
|
||||
"Creating profile...": "Profiel creeëren...",
|
||||
"This is not a valid name.": "Dit is geen geldige naam.",
|
||||
"Uploading profile...": "Profiel uploaden...",
|
||||
"songs": "liedjes",
|
||||
"YourName": "JeNaam",
|
||||
"discoverConnectHeader": "Verbinden met server",
|
||||
"discoverConnectServerAddress": "Serveradres:",
|
||||
"discoverConnectButton": "Verbinden",
|
||||
"Checking...": "Controleren...",
|
||||
"timeout": "Timeout",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Stuur toetsen automatisch",
|
||||
"keyboardButtonSend": "Verzenden"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Użytkownik:",
|
||||
"loginPassword": "Hasło:",
|
||||
"loginButton": "Login",
|
||||
"registerButton": "Stwórz Profil",
|
||||
"discoverReadQrButton": "Zeskanuj kod QR",
|
||||
"mainPageYourProfileLink": "Twój Profil",
|
||||
"mainPageYourProfileLinkDesc": "Edytuj swój profil",
|
||||
"mainPageCurrentSongLink": "Wybrana piosenka",
|
||||
"mainPageCurrentSongLinkDesc": "Wyświetl infromacje na temat wybranej piosenki",
|
||||
"mainPageSelectSong": "Wszystkie piosenki",
|
||||
"mainPageSelectSongDesc": "Lista dostępnych piosenek",
|
||||
"mainPageSelectPlaylist": "Wszystkie playlisty",
|
||||
"mainPageSelectPlaylistDesc": "Wyświetl wszystkei playlisty",
|
||||
"mainPageSelectProfile": "Profile",
|
||||
"mainPageSelectProfileDesc": "Pokaż wszystkie profile",
|
||||
"mainPageTakePhotoLink": "Zrób zdjęcie",
|
||||
"mainPageTakePhotoLinkDesc": "Robi zdjęcie i wyświetla je na końcu rundy",
|
||||
"mainPageKeyboard": "Klawiatura",
|
||||
"mainPageKeyboardDesc": "Wyślij klawisze",
|
||||
"mainPageSelectUserAdmin": "Administracja",
|
||||
"mainPageSelectUserAdminDesc": "Konfiguruj uprawnienia użytkowników",
|
||||
"mainPageLogoutLink": "Wyloguj",
|
||||
"mainPageLogoutLinkDesc": "Zamknij sesje",
|
||||
"selectProfileHeader": "Wszystkei profile",
|
||||
"displayProfileHeader": "Profile",
|
||||
"displayProfileName": "Imię:",
|
||||
"displayProfilePlayerType": "Rodzaj gracza:",
|
||||
"displayProfilePlayerTypeNormal": "Normalny",
|
||||
"displayProfilePlayerTypeGuest": "Gość",
|
||||
"displayProfilePlayerDifficulty": "Poziom trudności:",
|
||||
"displayProfilePlayerDifficultyEasy": "Łatwy",
|
||||
"displayProfilePlayerDifficultyNormal": "Normalny",
|
||||
"displayProfilePlayerDifficultyHard": "Trudny",
|
||||
"displayProfilePlayerPassword": "Nowe hasło:",
|
||||
"displayProfilePlayerSaveButton": "Zapisz i prześlij",
|
||||
"displaySongHeader": "Brak utworu",
|
||||
"displaySongArtist": "Artysta:",
|
||||
"displaySongGenre": "Gatunek:",
|
||||
"displaySongYear": "Rok:",
|
||||
"displaySongLanguage": "Język:",
|
||||
"displaySongIsDuet": "Duet",
|
||||
"popupVideoClose": "Zamknij",
|
||||
"selectSongHeader": "Wszystkei piosenki",
|
||||
"keyboardHeader": "Klawiatura",
|
||||
"keyboardButtonUp": "w górę",
|
||||
"keyboardButtonLeft": "lewo",
|
||||
"keyboardButtonRight": "prawo",
|
||||
"keyboardButtonDown": "w dół",
|
||||
"keyboardButtonEscape": "powrót",
|
||||
"keyboardButtonTab": "zakładka",
|
||||
"keyboardButtonReturn": "powrót",
|
||||
"keyboardButtonKeys": "Aby wysłać inne klawisze wpisz tutaj:",
|
||||
"selectUserAdminHeader": "Wszystkie profile",
|
||||
"displayUserAdminHeader": "Profile",
|
||||
"displayUserAdminContentSaveButton": "Zapisz",
|
||||
"selectPlaylistHeader": "Wybierz playliste",
|
||||
"displayPlaylistHeader": "Playlista",
|
||||
"displayPlaylistSaveButton": "Zapisz",
|
||||
"selectPlaylistAddPlaylistButton": "Dodaj",
|
||||
"Loading (external)...": "Ładowanie (z zewnątrz)",
|
||||
"Loading...": "Ładowanie...",
|
||||
"Creating...": "Tworzenie...",
|
||||
"Error...": "Błąd...",
|
||||
"No connection": "Brak połączenia",
|
||||
"No session": "Brak sesji",
|
||||
"Uploading photo...": "Wysyłanie zdjęcia",
|
||||
"Getting current song...": "Pobieranie piosenki",
|
||||
"Login...": "Login...",
|
||||
"Creating profile...": "Tworzenie profilu...",
|
||||
"This is not a valid name.": "To nie jest prawidłowe imię.",
|
||||
"Uploading profile...": "Aktualizowanie profilu...",
|
||||
"songs": "piosenki",
|
||||
"YourName": "TwojeImię",
|
||||
"discoverConnectHeader": "Połącz z serwerem",
|
||||
"discoverConnectServerAddress": "Adres serwera:",
|
||||
"discoverConnectButton": "Połącz",
|
||||
"Checking...": "Sprawdzanie...",
|
||||
"timeout": "Przekroczenie czasu",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Ctrl",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Wyślij klawisze",
|
||||
"keyboardButtonSend": "Wyślij"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Utilizador:",
|
||||
"loginPassword": "Palavra-passe:",
|
||||
"loginButton": "Entrar",
|
||||
"registerButton": "Criar Perfil",
|
||||
"discoverReadQrButton": "Digitalizar Código QR",
|
||||
"mainPageYourProfileLink": "O Seu Perfil",
|
||||
"mainPageYourProfileLinkDesc": "Editar o seu perfil",
|
||||
"mainPageCurrentSongLink": "Música Actual",
|
||||
"mainPageCurrentSongLinkDesc": "Mostrar informações sobre a canção actual",
|
||||
"mainPageSelectSong": "Todas as Músicas",
|
||||
"mainPageSelectSongDesc": "Mostrar todas as músicas disponíveis",
|
||||
"mainPageSelectPlaylist": "Todas as listas de reprodução",
|
||||
"mainPageSelectPlaylistDesc": "Mostrar todas as listas de reprodução",
|
||||
"mainPageSelectProfile": "Perfis",
|
||||
"mainPageSelectProfileDesc": "Mostrar todos os perfis",
|
||||
"mainPageTakePhotoLink": "Tirar Fotografia",
|
||||
"mainPageTakePhotoLinkDesc": "Tira uma foto e mostra-a no fim da ronda",
|
||||
"mainPageKeyboard": "Teclado",
|
||||
"mainPageKeyboardDesc": "Enviar teclas",
|
||||
"mainPageSelectUserAdmin": "Administração",
|
||||
"mainPageSelectUserAdminDesc": "Configurar privilégios do utilizador",
|
||||
"mainPageLogoutLink": "Sair",
|
||||
"mainPageLogoutLinkDesc": "Encerra a sessão",
|
||||
"selectProfileHeader": "Todos os perfis",
|
||||
"displayProfileHeader": "Perfil",
|
||||
"displayProfileName": "Nome:",
|
||||
"displayProfilePlayerType": "Tipo de Jogador:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Convidado",
|
||||
"displayProfilePlayerDifficulty": "Dificuldade:",
|
||||
"displayProfilePlayerDifficultyEasy": "Fácil",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Difícil",
|
||||
"displayProfilePlayerPassword": "Nova Palavra-passe:",
|
||||
"displayProfilePlayerSaveButton": "Gravar e enviar",
|
||||
"displaySongHeader": "Nenhuma canção seleccionada ",
|
||||
"displaySongArtist": "Artista:",
|
||||
"displaySongGenre": "Género:",
|
||||
"displaySongYear": "Ano:",
|
||||
"displaySongLanguage": "Língua:",
|
||||
"displaySongIsDuet": "Dueto:",
|
||||
"popupVideoClose": "Fechar",
|
||||
"selectSongHeader": "Todas as Músicas",
|
||||
"keyboardHeader": "Teclado",
|
||||
"keyboardButtonUp": "cima",
|
||||
"keyboardButtonLeft": "esquerda",
|
||||
"keyboardButtonRight": "direita",
|
||||
"keyboardButtonDown": "baixo",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "enter",
|
||||
"keyboardButtonKeys": "Para enviar outras teclas escreve-as aqui:",
|
||||
"selectUserAdminHeader": "Todos os perfis",
|
||||
"displayUserAdminHeader": "Perfil",
|
||||
"displayUserAdminContentSaveButton": "Gravar",
|
||||
"selectPlaylistHeader": "Selecciona uma lista de reprodução",
|
||||
"displayPlaylistHeader": "lista de reprodução",
|
||||
"displayPlaylistSaveButton": "Gravar",
|
||||
"selectPlaylistAddPlaylistButton": "Adicionar",
|
||||
"Loading (external)...": "A carregar (externo)...",
|
||||
"Loading...": "A carregar...",
|
||||
"Creating...": "A Criar...",
|
||||
"Error...": "Erro...",
|
||||
"No connection": "Sem ligação",
|
||||
"No session": "Sem sessão",
|
||||
"Uploading photo...": "A enviar fotografia...",
|
||||
"Getting current song...": "A transferir a música actual...",
|
||||
"Login...": "Entrar...",
|
||||
"Creating profile...": "A criar perfil...",
|
||||
"This is not a valid name.": "O nome não é válido.",
|
||||
"Uploading profile...": "A enviar perfil...",
|
||||
"songs": "músicas",
|
||||
"YourName": "O Teu Nome",
|
||||
"discoverConnectHeader": "Ligar ao servidor",
|
||||
"discoverConnectServerAddress": "Endereço do Servidor:",
|
||||
"discoverConnectButton": "Ligar",
|
||||
"Checking...": "A verificar...",
|
||||
"timeout": "Tempo de espera excedido",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Enviar teclas automáticamente",
|
||||
"keyboardButtonSend": "Enviar"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Пользователь:",
|
||||
"loginPassword": "Пароль:",
|
||||
"loginButton": "Логин",
|
||||
"registerButton": "Создать профиль",
|
||||
"discoverReadQrButton": "Сканировать QR-код",
|
||||
"mainPageYourProfileLink": "Ваш профиль",
|
||||
"mainPageYourProfileLinkDesc": "Редактировать ваш профиль",
|
||||
"mainPageCurrentSongLink": "Текущая песня",
|
||||
"mainPageCurrentSongLinkDesc": "Отображение информации о текущей песне",
|
||||
"mainPageSelectSong": "Все песни",
|
||||
"mainPageSelectSongDesc": "Список всех доступных песен",
|
||||
"mainPageSelectPlaylist": "Все плейлисты",
|
||||
"mainPageSelectPlaylistDesc": "Список всех плейлистов",
|
||||
"mainPageSelectProfile": "Профили",
|
||||
"mainPageSelectProfileDesc": "Показать все профили",
|
||||
"mainPageTakePhotoLink": "Выбрать Фото",
|
||||
"mainPageTakePhotoLinkDesc": "Выбрать фотографию и отображать ее в конце текущего раунда",
|
||||
"mainPageKeyboard": "Клавиатура",
|
||||
"mainPageKeyboardDesc": "Отправить ключи",
|
||||
"mainPageSelectUserAdmin": "Администрирование",
|
||||
"mainPageSelectUserAdminDesc": "Настроить права пользователя",
|
||||
"mainPageLogoutLink": "Выход из системы",
|
||||
"mainPageLogoutLinkDesc": "Закрыть сессию",
|
||||
"selectProfileHeader": "Все профили",
|
||||
"displayProfileHeader": "Профиль",
|
||||
"displayProfileName": "Имя:",
|
||||
"displayProfilePlayerType": "Тип Игрока:",
|
||||
"displayProfilePlayerTypeNormal": "Обычный",
|
||||
"displayProfilePlayerTypeGuest": "Гость",
|
||||
"displayProfilePlayerDifficulty": "Сложность:",
|
||||
"displayProfilePlayerDifficultyEasy": "Легко",
|
||||
"displayProfilePlayerDifficultyNormal": "Нормально",
|
||||
"displayProfilePlayerDifficultyHard": "Сложно",
|
||||
"displayProfilePlayerPassword": "Новый Пароль:",
|
||||
"displayProfilePlayerSaveButton": "Сохранить и загрузить",
|
||||
"displaySongHeader": "Нет текущей песни",
|
||||
"displaySongArtist": "Артист:",
|
||||
"displaySongGenre": "Жанр:",
|
||||
"displaySongYear": "Год:",
|
||||
"displaySongLanguage": "Язык:",
|
||||
"displaySongIsDuet": "Дуэт:",
|
||||
"popupVideoClose": "Закрыть",
|
||||
"selectSongHeader": "Все песни",
|
||||
"keyboardHeader": "Клавиатура",
|
||||
"keyboardButtonUp": "вверх",
|
||||
"keyboardButtonLeft": "влево",
|
||||
"keyboardButtonRight": "вправо",
|
||||
"keyboardButtonDown": "вниз",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "return",
|
||||
"keyboardButtonKeys": "Чтобы отправить другие ключи введите здесь:",
|
||||
"selectUserAdminHeader": "Все профили",
|
||||
"displayUserAdminHeader": "Профиль",
|
||||
"displayUserAdminContentSaveButton": "Сохранить",
|
||||
"selectPlaylistHeader": "Выборать из плейлиста",
|
||||
"displayPlaylistHeader": "Плейлист",
|
||||
"displayPlaylistSaveButton": "Сохранить",
|
||||
"selectPlaylistAddPlaylistButton": "Добавить",
|
||||
"Loading (external)...": "Загрузка (внешняя)...",
|
||||
"Loading...": "Загрузка...",
|
||||
"Creating...": "Создание...",
|
||||
"Error...": "Ошибка...",
|
||||
"No connection": "Нет соединения",
|
||||
"No session": "Нет сеанса",
|
||||
"Uploading photo...": "Загрузка фото..",
|
||||
"Getting current song...": "Получение текущей песни...",
|
||||
"Login...": "Логин...",
|
||||
"Creating profile...": "Создание профиля...",
|
||||
"This is not a valid name.": "Это неверное имя.",
|
||||
"Uploading profile...": "Загрузка профиля...",
|
||||
"songs": "песни",
|
||||
"YourName": "Ваше имя",
|
||||
"discoverConnectHeader": "Подключиться к серверу",
|
||||
"discoverConnectServerAddress": "Адрес сервера:",
|
||||
"discoverConnectButton": "Соединение",
|
||||
"Checking...": "Проверка...",
|
||||
"timeout": "Время ожидания",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Автоматическая отправка ключей",
|
||||
"keyboardButtonSend": "Отправить"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Användarnamn:",
|
||||
"loginPassword": "Lösenord:",
|
||||
"loginButton": "Logga in",
|
||||
"registerButton": "Skapa profil",
|
||||
"discoverReadQrButton": "Scanna QR-kod",
|
||||
"mainPageYourProfileLink": "Din profil",
|
||||
"mainPageYourProfileLinkDesc": "Ändra din profil",
|
||||
"mainPageCurrentSongLink": "Nuvarande låt",
|
||||
"mainPageCurrentSongLinkDesc": "Visa information om nuvarande låt",
|
||||
"mainPageSelectSong": "Alla låtar",
|
||||
"mainPageSelectSongDesc": "Lista alla tillgängliga låtar",
|
||||
"mainPageSelectPlaylist": "Alla spellistor",
|
||||
"mainPageSelectPlaylistDesc": "Visa alla spellistor",
|
||||
"mainPageSelectProfile": "Profiler",
|
||||
"mainPageSelectProfileDesc": "Visa alla profiler",
|
||||
"mainPageTakePhotoLink": "Ta foto",
|
||||
"mainPageTakePhotoLinkDesc": "Tar ett foto och visar det i slutet av rundan",
|
||||
"mainPageKeyboard": "Tangentbord",
|
||||
"mainPageKeyboardDesc": "Skicka tangenttryck",
|
||||
"mainPageSelectUserAdmin": "Administration",
|
||||
"mainPageSelectUserAdminDesc": "Konfigurera användarrättigheter",
|
||||
"mainPageLogoutLink": "Logga ut",
|
||||
"mainPageLogoutLinkDesc": "Avslutar sessionen",
|
||||
"selectProfileHeader": "Alla profiler",
|
||||
"displayProfileHeader": "Profil",
|
||||
"displayProfileName": "Namn:",
|
||||
"displayProfilePlayerType": "Spelartyp:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Gäst",
|
||||
"displayProfilePlayerDifficulty": "Svårighetsgrad:",
|
||||
"displayProfilePlayerDifficultyEasy": "Lätt",
|
||||
"displayProfilePlayerDifficultyNormal": "Medel",
|
||||
"displayProfilePlayerDifficultyHard": "Svår",
|
||||
"displayProfilePlayerPassword": "Nytt lösenord:",
|
||||
"displayProfilePlayerSaveButton": "Spara och ladda upp",
|
||||
"displaySongHeader": "Ingen nuvarande låt",
|
||||
"displaySongArtist": "Artist:",
|
||||
"displaySongGenre": "Genre:",
|
||||
"displaySongYear": "År:",
|
||||
"displaySongLanguage": "Språk:",
|
||||
"displaySongIsDuet": "Duett:",
|
||||
"popupVideoClose": "Stäng",
|
||||
"selectSongHeader": "Alla låtar",
|
||||
"keyboardHeader": "Tangentbord",
|
||||
"keyboardButtonUp": "upp",
|
||||
"keyboardButtonLeft": "vänster",
|
||||
"keyboardButtonRight": "höger",
|
||||
"keyboardButtonDown": "ner",
|
||||
"keyboardButtonEscape": "avbryt",
|
||||
"keyboardButtonTab": "tabb",
|
||||
"keyboardButtonReturn": "retur",
|
||||
"keyboardButtonKeys": "För att skicka andra tangenttryck skriv här:",
|
||||
"selectUserAdminHeader": "Alla profiler",
|
||||
"displayUserAdminHeader": "Profil",
|
||||
"displayUserAdminContentSaveButton": "Spara",
|
||||
"selectPlaylistHeader": "Välj en spellista",
|
||||
"displayPlaylistHeader": "Spellista",
|
||||
"displayPlaylistSaveButton": "Spara",
|
||||
"selectPlaylistAddPlaylistButton": "Lägg till",
|
||||
"Loading (external)...": "Laddar (extern)...",
|
||||
"Loading...": "Laddar...",
|
||||
"Creating...": "Skapar...",
|
||||
"Error...": "Fel...",
|
||||
"No connection": "Ingen anslutning",
|
||||
"No session": "Ingen session",
|
||||
"Uploading photo...": "Laddar upp foto...",
|
||||
"Getting current song...": "Hämtar nuvarande låt...",
|
||||
"Login...": "Loggar in...",
|
||||
"Creating profile...": "Skapar profil...",
|
||||
"This is not a valid name.": "Detta är inget giltigt namn.",
|
||||
"Uploading profile...": "Laddar upp profil...",
|
||||
"songs": "låtar",
|
||||
"YourName": "Ditt namn",
|
||||
"discoverConnectHeader": "Anslut till server",
|
||||
"discoverConnectServerAddress": "Serveradress:",
|
||||
"discoverConnectButton": "Anslut",
|
||||
"Checking...": "Kontrollerar...",
|
||||
"timeout": "Timeout",
|
||||
"keyboardButtonShift": "Skift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Ctrl",
|
||||
"keyboardButtonBackspace": "Backsteg",
|
||||
"keyboardAutoSend": "Autoskicka knappar",
|
||||
"keyboardButtonSend": "Skicka"
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
{
|
||||
"loginName": "Kullanıcı:",
|
||||
"loginPassword": "Şifre:",
|
||||
"loginButton": "Giriş",
|
||||
"registerButton": "Profil Oluştur",
|
||||
"discoverReadQrButton": "QR Kodunu Tarat",
|
||||
"mainPageYourProfileLink": "Profiliniz",
|
||||
"mainPageYourProfileLinkDesc": "Profilinizi düzenleyin",
|
||||
"mainPageCurrentSongLink": "Current Song",
|
||||
"mainPageCurrentSongLinkDesc": "Display informations about the current song",
|
||||
"mainPageSelectSong": "Tüm şarkılar",
|
||||
"mainPageSelectSongDesc": "Tüm mevcut şarkıları listele",
|
||||
"mainPageSelectPlaylist": "Tüm çalma listeleri",
|
||||
"mainPageSelectPlaylistDesc": "Lists all playlists",
|
||||
"mainPageSelectProfile": "Profiller",
|
||||
"mainPageSelectProfileDesc": "Shows all profiles",
|
||||
"mainPageTakePhotoLink": "Fotoğraf Çek",
|
||||
"mainPageTakePhotoLinkDesc": "Takes a photo and displays it at the end of the current round",
|
||||
"mainPageKeyboard": "Klavye",
|
||||
"mainPageKeyboardDesc": "Send keys",
|
||||
"mainPageSelectUserAdmin": "Yönetim",
|
||||
"mainPageSelectUserAdminDesc": "Kullanıcı haklarını yapılandır",
|
||||
"mainPageLogoutLink": "Çıkış Yap",
|
||||
"mainPageLogoutLinkDesc": "Closes the session",
|
||||
"selectProfileHeader": "Tüm Profiller",
|
||||
"displayProfileHeader": "Profil",
|
||||
"displayProfileName": "İsim:",
|
||||
"displayProfilePlayerType": "Oyuncu Türü:",
|
||||
"displayProfilePlayerTypeNormal": "Normal",
|
||||
"displayProfilePlayerTypeGuest": "Misafir",
|
||||
"displayProfilePlayerDifficulty": "Zorluk:",
|
||||
"displayProfilePlayerDifficultyEasy": "Kolay",
|
||||
"displayProfilePlayerDifficultyNormal": "Normal",
|
||||
"displayProfilePlayerDifficultyHard": "Zor",
|
||||
"displayProfilePlayerPassword": "Yeni Şifre:",
|
||||
"displayProfilePlayerSaveButton": "Kaydet ve yükle",
|
||||
"displaySongHeader": "Mevcut şarkı yok",
|
||||
"displaySongArtist": "Sanatçı:",
|
||||
"displaySongGenre": "Tür:",
|
||||
"displaySongYear": "Yıl:",
|
||||
"displaySongLanguage": "Dil:",
|
||||
"displaySongIsDuet": "Düet:",
|
||||
"popupVideoClose": "Kapat",
|
||||
"selectSongHeader": "Tüm şarkılar",
|
||||
"keyboardHeader": "Klavye",
|
||||
"keyboardButtonUp": "yukarı",
|
||||
"keyboardButtonLeft": "sol",
|
||||
"keyboardButtonRight": "sağ",
|
||||
"keyboardButtonDown": "aşağı",
|
||||
"keyboardButtonEscape": "escape",
|
||||
"keyboardButtonTab": "tab",
|
||||
"keyboardButtonReturn": "return",
|
||||
"keyboardButtonKeys": "To send other keys type here:",
|
||||
"selectUserAdminHeader": "Tüm profiller",
|
||||
"displayUserAdminHeader": "Profil",
|
||||
"displayUserAdminContentSaveButton": "Kaydet",
|
||||
"selectPlaylistHeader": "Çalma listesi seç",
|
||||
"displayPlaylistHeader": "Çalma listesi",
|
||||
"displayPlaylistSaveButton": "Kaydet",
|
||||
"selectPlaylistAddPlaylistButton": "Ekle",
|
||||
"Loading (external)...": "Yükleniyor (harici)...",
|
||||
"Loading...": "Yükleniyor...",
|
||||
"Creating...": "Oluşturuluyor...",
|
||||
"Error...": "Hata...",
|
||||
"No connection": "Bağlantı yok",
|
||||
"No session": "No session",
|
||||
"Uploading photo...": "Fotoğraf yükleniyor...",
|
||||
"Getting current song...": "Getting current song...",
|
||||
"Login...": "Login...",
|
||||
"Creating profile...": "Profil oluşturuluyor...",
|
||||
"This is not a valid name.": "Bu geçerli bir isim değil.",
|
||||
"Uploading profile...": "Profil yükleniyor...",
|
||||
"songs": "şarkılar",
|
||||
"YourName": "YourName",
|
||||
"discoverConnectHeader": "Sunucuya bağlan",
|
||||
"discoverConnectServerAddress": "Sunucu adresi:",
|
||||
"discoverConnectButton": "Bağlan",
|
||||
"Checking...": "Kontrol ediliyor...",
|
||||
"timeout": "Zaman aşımı",
|
||||
"keyboardButtonShift": "Shift",
|
||||
"keyboardButtonAlt": "Alt",
|
||||
"keyboardButtonCtrl": "Control",
|
||||
"keyboardButtonBackspace": "Backspace",
|
||||
"keyboardAutoSend": "Auto send keys",
|
||||
"keyboardButtonSend": "Send"
|
||||
}
|
||||
@@ -434,6 +434,7 @@ namespace VocaluxeLib
|
||||
StatisticsDetail,
|
||||
Jukebox,
|
||||
JukeboxPlayer,
|
||||
WebQueue,
|
||||
|
||||
CountEntry //Leave this as last entry and never use it!
|
||||
}
|
||||
|
||||