rwdmpd 0.06
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Readme.txt +475 -0
- data/bin/rwdmpd +19 -0
- data/code/01rwdcore/01rwdcore.rb +29 -0
- data/code/01rwdcore/02helptexthashbegin.rb +4 -0
- data/code/01rwdcore/03helptexthash.rb +23 -0
- data/code/01rwdcore/04helptextend.rb +6 -0
- data/code/01rwdcore/jumplinkcommand.rb +26 -0
- data/code/01rwdcore/openhelpwindow.rb +31 -0
- data/code/01rwdcore/returntomain.rb +10 -0
- data/code/01rwdcore/rundocuments.rb +10 -0
- data/code/01rwdcore/runeditconfiguration.rb +10 -0
- data/code/01rwdcore/runhelpabout.rb +10 -0
- data/code/01rwdcore/runopentinkerdocument.rb +7 -0
- data/code/01rwdcore/rwdtinkerversion.rb +22 -0
- data/code/01rwdcore/rwdwindowreturn.rb +9 -0
- data/code/01rwdcore/selectiontab.rb +9 -0
- data/code/01rwdcore/setuphelpaboutoptions.rb +13 -0
- data/code/01rwdcore/setuptinkerdocuments.rb +6 -0
- data/code/01rwdcore/test_cases.rb +109 -0
- data/code/01rwdcore/test_harness.rb +13 -0
- data/code/01rwdcore/uploadreturns.rb +62 -0
- data/code/dd0viewphoto/dd0viewphoto.rb +3 -0
- data/code/superant.com.rwdmp3/0uninstallapplet.rb +11 -0
- data/code/superant.com.rwdmp3/clearscreendisplay.rb +7 -0
- data/code/superant.com.rwdmp3/controlmpd.rb +139 -0
- data/code/superant.com.rwdmp3/helptexthashrwdmp3.rb +41 -0
- data/code/superant.com.rwdmp3/listplaylistfiles.rb +12 -0
- data/code/superant.com.rwdmp3/loadconfigurationrecord.rb +22 -0
- data/code/superant.com.rwdmp3/loadconfigurationvariables.rb +13 -0
- data/code/superant.com.rwdmp3/loadplaylistrecord.rb +19 -0
- data/code/superant.com.rwdmp3/mpd_client.rb +41 -0
- data/code/superant.com.rwdmp3/mpd_seek.rb +23 -0
- data/code/superant.com.rwdmp3/openhelpwindowrwdmp3.rb +25 -0
- data/code/superant.com.rwdmp3/runrwdmpdwindow.rb +10 -0
- data/code/superant.com.rwdmp3/rwdtinkerversion.rb +10 -0
- data/code/superant.com.rwdmp3/saveconfigurationrecord.rb +19 -0
- data/code/superant.com.rwdmp3/saveplaylistrecord.rb +18 -0
- data/code/superant.com.rwdmp3/startmp3server.rb +16 -0
- data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/helptexthashtinkerwin2.rb +61 -0
- data/code/superant.com.rwdtinkerbackwindow/initiateapplets.rb +240 -0
- data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +34 -0
- data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +20 -0
- data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +12 -0
- data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +53 -0
- data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +12 -0
- data/code/superant.com.rwdtinkerbackwindow/listzips.rb +33 -0
- data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +22 -0
- data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -0
- data/code/superant.com.rwdtinkerbackwindow/network.rb +87 -0
- data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +38 -0
- data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +24 -0
- data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +46 -0
- data/code/superant.com.rwdtinkerbackwindow/removeappletvariables.rb +52 -0
- data/code/superant.com.rwdtinkerbackwindow/runremoteinstall.rb +11 -0
- data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +15 -0
- data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +13 -0
- data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -0
- data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +22 -0
- data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +24 -0
- data/code/zz0applicationend/zz0end.rb +4 -0
- data/configuration/language.dist +8 -0
- data/configuration/rwdapplicationidentity.dist +3 -0
- data/configuration/rwdtinker.dist +15 -0
- data/configuration/rwdwmpd-0.06.dist +14 -0
- data/configuration/tinkerwin2variables.dist +18 -0
- data/gui/00coreguibegin/applicationguitop.rwd +4 -0
- data/gui/frontwindow0/cc0openphoto.rwd +22 -0
- data/gui/frontwindowselections/00selectiontabbegin.rwd +11 -0
- data/gui/frontwindowselections/jumplinkcommands.rwd +15 -0
- data/gui/frontwindowselections/wwselectionend.rwd +3 -0
- data/gui/frontwindowtdocuments/00documentbegin.rwd +6 -0
- data/gui/frontwindowtdocuments/tinkerdocuments.rwd +14 -0
- data/gui/frontwindowtdocuments/zzdocumentend.rwd +8 -0
- data/gui/helpaboutbegin/zzzrwdlasttab.rwd +6 -0
- data/gui/helpaboutbegin/zzzzhelpscreenstart.rwd +3 -0
- data/gui/helpaboutbegin/zzzzzzhelpabouttab.rwd +15 -0
- data/gui/helpaboutzend/helpscreenend.rwd +3 -0
- data/gui/helpaboutzend/zhelpscreenstart2.rwd +3 -0
- data/gui/helpaboutzend/zzzzhelpabout2.rwd +15 -0
- data/gui/helpaboutzend/zzzzhelpscreen2end.rwd +3 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/10appletbegin.rwd +4 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/20rwdmpd.rwd +37 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/25rwdseek.rwd +23 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/30editplaylist.rwd +27 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/88viewconfiguration.rwd +32 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/89rwddiagnostics.rwd +26 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/90jumplinkcommands.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.rwdmp3/9end.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/1appname.rwd +5 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/40rwdlistzips.rwd +41 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/45installremotezip.rwd +44 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/50rwdlistapplets.rwd +44 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/60editconfiguration.rwd +30 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/70rwddiagnostics.rwd +29 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/81jumplinkcommands.rwd +17 -0
- data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/9backend.rwd +6 -0
- data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/1appname.rwd +31 -0
- data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/9end.rwd +4 -0
- data/gui/tinkerbackwindows/superant.com.versionwindow/1appname.rwd +19 -0
- data/gui/tinkerbackwindows/superant.com.versionwindow/helpaboutwindow.rwd +17 -0
- data/gui/zzcoreguiend/yy9rwdend.rwd +4 -0
- data/init.rb +277 -0
- data/installed/mpdmusicdata2.inf +2 -0
- data/installed/rwdwmpd-0.06.inf +10 -0
- data/installed/temp.rb +1 -0
- data/lang/en/rwdcore/languagefile.rb +58 -0
- data/lang/es/rwdcore/languagefile-es.rb +62 -0
- data/lang/fr/rwdcore/languagefile.rb +64 -0
- data/lang/jp/rwdcore/languagefile.rb +72 -0
- data/lang/nl/rwdcore/languagefile.rb +75 -0
- data/lib/librmpd.rb +1152 -0
- data/lib/mpdserver.rb +1204 -0
- data/lib/rconftool.rb +387 -0
- data/lib/rwd/browser.rb +123 -0
- data/lib/rwd/ftools.rb +174 -0
- data/lib/rwd/mime.rb +328 -0
- data/lib/rwd/net.rb +876 -0
- data/lib/rwd/ruby.rb +889 -0
- data/lib/rwd/rwd.rb +1422 -0
- data/lib/rwd/sgml.rb +236 -0
- data/lib/rwd/thread.rb +63 -0
- data/lib/rwd/tree.rb +371 -0
- data/lib/rwd/xml.rb +101 -0
- data/lib/rwdthemes/default.rwd +317 -0
- data/lib/rwdthemes/pda.rwd +72 -0
- data/lib/rwdthemes/windowslike.rwd +171 -0
- data/lib/zip/ioextras.rb +114 -0
- data/lib/zip/stdrubyext.rb +111 -0
- data/lib/zip/tempfile_bugfixed.rb +195 -0
- data/lib/zip/zip.rb +1378 -0
- data/lib/zip/zipfilesystem.rb +558 -0
- data/lib/zip/ziprequire.rb +61 -0
- data/music/classicalmues.mp3 +0 -0
- data/rwd_files/HowTo_Mpd.txt +136 -0
- data/rwd_files/HowTo_Tinker.txt +482 -0
- data/rwd_files/HowTo_TinkerWin2.txt +202 -0
- data/rwd_files/Readme.txt +57 -0
- data/rwd_files/RubyWebDialogs.html +6 -0
- data/rwd_files/favicon.ico +0 -0
- data/rwd_files/rdoc-style.css +175 -0
- data/rwd_files/rwdapplications.html +54 -0
- data/rwd_files/tinker.png +0 -0
- data/rwdconfig.dist +22 -0
- data/rwdmpd.rb +1 -0
- data/tests/RubyGauge.rb +179 -0
- data/tests/checkdepends.sh +4 -0
- data/tests/cleancnf.sh +6 -0
- data/tests/makedist-rwdwmpd.rb +58 -0
- data/tests/makedist.rb +66 -0
- data/tests/rdep.rb +354 -0
- data/tests/totranslate.lang +93 -0
- data/zips/rwdwaddresses-1.06.zip +0 -0
- data/zips/rwdwcalc-0.62.zip +0 -0
- data/zips/rwdwfoldeditor-0.04.zip +0 -0
- data/zips/rwdwgutenberg-0.09.zip +0 -0
- data/zips/rwdwmpd-0.06.zip +0 -0
- data/zips/rwdwruby-1.07.zip +0 -0
- data/zips/temp.rb +1 -0
- data/zips/tinkerbellw-0.02.zip +0 -0
- data/zips/wrubyslippers-1.06.zip +0 -0
- metadata +220 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# rwdwmpd - music controller
|
|
2
|
+
code/superant.com.rwdmp3
|
|
3
|
+
rwd_files/HowTo_Mpd.txt
|
|
4
|
+
configuration/rwdwmpd-0.06.dist
|
|
5
|
+
configuration/rwdwmpd-0.06.cnf
|
|
6
|
+
gui/tinkerbackwindows/superant.com.rwdmp3
|
|
7
|
+
tests/makedist-rwdwmpd.rb
|
|
8
|
+
tests/gemspec-rwdwmpd
|
|
9
|
+
lib/mpdserver.rb
|
|
10
|
+
lib/librmpd.rb
|
data/installed/temp.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# this file does nothing
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# English Language files for RwdTinker core
|
|
2
|
+
|
|
3
|
+
:applet_installed => '"applet installed!"',
|
|
4
|
+
:application_version => '"Application Version"',
|
|
5
|
+
:clear => "Clear",
|
|
6
|
+
:cancel => "Cancel",
|
|
7
|
+
:clickfor_version => "Click for Version" ,
|
|
8
|
+
:clickbelowtoviewlistof_zip => '"click below to view lists of zips"',
|
|
9
|
+
:documents => '"Documents"',
|
|
10
|
+
:edit => "edit" ,
|
|
11
|
+
:file_name => '"File Name:"',
|
|
12
|
+
:fill_record => '"Fill Record"',
|
|
13
|
+
:help => '"Help"',
|
|
14
|
+
:help_about => '"Help About"',
|
|
15
|
+
:install_applet => '"install (rwdtinker) applet"',
|
|
16
|
+
:jumptoapplication_location => '"Jump to Application Location"',
|
|
17
|
+
:list_applets => '"Remove Applets"',
|
|
18
|
+
:listappletsinthegem_directory => '"List applets in the Gem Directory"',
|
|
19
|
+
:listappletsavailablefor_installation => "List applets available for installation",
|
|
20
|
+
:list_files => '"List Files"',
|
|
21
|
+
:list_installed_gems => '"List installed Gems"' ,
|
|
22
|
+
:list_photos => '"List Photos"',
|
|
23
|
+
:list_zips => '"List Zips"',
|
|
24
|
+
:listzipdirappletsavailable => '"List (zip directory) applets available for installation"',
|
|
25
|
+
:menu_panel => '"Menu Panel"',
|
|
26
|
+
:module_unknown => '"Unknown Module"',
|
|
27
|
+
:next => '"Next"',
|
|
28
|
+
:open => "Open",
|
|
29
|
+
:open_document => '"Open Document"',
|
|
30
|
+
:openselectedhelp_about => '"Open selected help about"',
|
|
31
|
+
:reload_variables => '"Reload Variables"' ,
|
|
32
|
+
:remove_applet => '"remove applet"',
|
|
33
|
+
:return => "Return",
|
|
34
|
+
:rwdtinker_window_2 => "RwdTinker Window 2",
|
|
35
|
+
:rwdtinker => "RwdTinker",
|
|
36
|
+
:rwdtinker_back_window => '"RwdTinker Back Window"',
|
|
37
|
+
:rwdtinker_help => '"RwdTinker Help"',
|
|
38
|
+
:rwdtinker_help_window => '"RwdTinker Help Window"',
|
|
39
|
+
:showjump_links => '"Show Jump Links"',
|
|
40
|
+
:showdocument_list => '"Show Document List"',
|
|
41
|
+
:showhelpabout_links => '"Show Help About Links"',
|
|
42
|
+
|
|
43
|
+
:save => "Save" ,
|
|
44
|
+
:save_changes => '"Save Changes"',
|
|
45
|
+
:selection_panel => '"Menu Panel"',
|
|
46
|
+
:selection_tab => '"Menu Tab"',
|
|
47
|
+
:tinker_logo => "Tinker Logo",
|
|
48
|
+
:tinkerback_window => '"Tinker Back Window"',
|
|
49
|
+
:viewapplet_contents => '"View Applet Contents"',
|
|
50
|
+
:viewalreadyinstalled_applications => '"View already installed GEM applications"',
|
|
51
|
+
:viewinstalled_text => '"View Install Text"',
|
|
52
|
+
:view_platform => '"view platform"',
|
|
53
|
+
:viewplatform_information => '"View Platform Information"',
|
|
54
|
+
:view_event => '"View event"',
|
|
55
|
+
:viewinstall_text => '"View Install Text"' ,
|
|
56
|
+
:viewlistinstall_files => '"View List of Installed Files"',
|
|
57
|
+
:view_photo => '"View Photo"',
|
|
58
|
+
:window => "Window" ,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Spanish Language files for RwdTinker core
|
|
2
|
+
|
|
3
|
+
:applet_installed => '"applet instalado!"',
|
|
4
|
+
:application_version => '"Application Version"',
|
|
5
|
+
:clear => "Clear",
|
|
6
|
+
:cancel => "Cancelaci�n",
|
|
7
|
+
:clickfor_version => '"click para version"' ,
|
|
8
|
+
:clickbelowtoviewlistof_zip => '"click abajo a ver lista de zips"',
|
|
9
|
+
:documents => '"Documentos"',
|
|
10
|
+
:edit => "Editar" ,
|
|
11
|
+
:file_name => '"Fila Nombre:"',
|
|
12
|
+
:fill_record => '"Fill Record"',
|
|
13
|
+
:help => '"Ayuda"',
|
|
14
|
+
:help_about => '"Ayuda sobre"',
|
|
15
|
+
:install_applet => '"instale (rwdtinker) applet"',
|
|
16
|
+
:jumptoapplication_location => '"Jump to Application Location"',
|
|
17
|
+
:list_applets => '"List Applets"',
|
|
18
|
+
:listappletsavailablefor_installation => "List applets available for installation",
|
|
19
|
+
:listappletsinthegem_directory => '"List applets in the Gem Directory"',
|
|
20
|
+
|
|
21
|
+
:list_files => '"Lista de Archivos"',
|
|
22
|
+
:list_installed_gems => '"Lista de Instalado Gems"' ,
|
|
23
|
+
:list_photos => '"Lista de Photos"',
|
|
24
|
+
:list_zips => '"List Zips"',
|
|
25
|
+
:listzipdirappletsavailable => '"Lista (zip directory) applets available for installation"',
|
|
26
|
+
:menu_panel => '"panel de herramientas"',
|
|
27
|
+
:module_unknown => '"Module desconocido"',
|
|
28
|
+
:next => "Siguiente",
|
|
29
|
+
:open => "Abrir",
|
|
30
|
+
:open_document => '"Abrir documento"',
|
|
31
|
+
:openselectedhelp_about => '"Open selected help about"',
|
|
32
|
+
:reload_variables => '"Reload Variables"' ,
|
|
33
|
+
:remove_applet => '"remove applet"',
|
|
34
|
+
:return => "anterior",
|
|
35
|
+
:rwdtinker_window_2 => '"RwdTinker Window 2"',
|
|
36
|
+
:rwdtinker => "RwdTinker",
|
|
37
|
+
:rwdtinker_back_window => '"RwdTinker Ventana Trasera"',
|
|
38
|
+
:rwdtinker_help => '"RwdTinker Ayuda"',
|
|
39
|
+
:rwdtinker_help_window => '"RwdTinker Ventana Ayuda"',
|
|
40
|
+
:showdocument_list => '"Show Document List"',
|
|
41
|
+
:showhelpabout_links => '"Show Help About Links"',
|
|
42
|
+
|
|
43
|
+
:showjump_links => '"Mostrar enlace saltar"',
|
|
44
|
+
|
|
45
|
+
:save => "Guardar" ,
|
|
46
|
+
:save_changes => '"Guardar los cambios"',
|
|
47
|
+
:rwdtinker => "RwdTinker",
|
|
48
|
+
:selection_panel => '"Panel de Selecci�n"',
|
|
49
|
+
|
|
50
|
+
:tinker_logo => '"Insignia de Tinker"',
|
|
51
|
+
:selection_tab => '"Selection Tab"',
|
|
52
|
+
:tinkerback_window => '"Tinker Back Window"',
|
|
53
|
+
:viewapplet_contents => '"View Applet Contents"',
|
|
54
|
+
:viewalreadyinstalled_applications => '"View already installed GEM applications"',
|
|
55
|
+
:viewinstalled_text => '"View Install Text"',
|
|
56
|
+
:view_platform => '"view platform"',
|
|
57
|
+
:viewplatform_information => '"View Platform Information"',
|
|
58
|
+
:view_event => '"Ver evento"',
|
|
59
|
+
:viewinstall_text => '"Ver Texto"' ,
|
|
60
|
+
:viewlistinstall_files => '"View List of Installed Files"',
|
|
61
|
+
:view_photo => '"Ver Photo"' ,
|
|
62
|
+
:window => "Ventana" ,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# English Language files for RwdTinker core
|
|
2
|
+
|
|
3
|
+
:applet_installed => '"applet installed!"',
|
|
4
|
+
:application_version => '"Application Version"',
|
|
5
|
+
:clear => "Clear",
|
|
6
|
+
:cancel => "Cancel",
|
|
7
|
+
:clickfor_version => "Click for Version" ,
|
|
8
|
+
:clickbelowtoviewlistof_zip => '"click below to view lists of zips"',
|
|
9
|
+
:documents => '"Documents"',
|
|
10
|
+
:edit => "edit" ,
|
|
11
|
+
:file_name => '"File Name:"',
|
|
12
|
+
:fill_record => '"Fill Record"',
|
|
13
|
+
:gemcommands => '"Gem Commands"',
|
|
14
|
+
:gemfiles => '"Gem Files"' ,
|
|
15
|
+
:gemdocs => '"Gem Documents"' ,
|
|
16
|
+
:gem_name => '"Gem Name"' ,
|
|
17
|
+
:help => '"Help"',
|
|
18
|
+
:help_about => '"Help About"',
|
|
19
|
+
:installgem => '"Install Gem"' ,
|
|
20
|
+
:install_applet => '"install (rwdtinker) applet"',
|
|
21
|
+
:jumptoapplication_location => '"Jump to Application Location"',
|
|
22
|
+
:list_applets => '"List Applets"',
|
|
23
|
+
:listappletsinthegem_directory => '"List applets in the Gem Directory"',
|
|
24
|
+
:listappletsavailablefor_installation => "List applets available for installation",
|
|
25
|
+
:list_files => '"List Files"',
|
|
26
|
+
:list_installed_gems => '"List installed Gems"' ,
|
|
27
|
+
:list_photos => '"List Photos"',
|
|
28
|
+
:list_zips => '"List Zips"',
|
|
29
|
+
:listzipdirappletsavailable => '"List (zip directory) applets available for installation"',
|
|
30
|
+
:menu_panel => '"Menu Panel"',
|
|
31
|
+
:module_unknown => '"Unknown Module"',
|
|
32
|
+
:next => '"Next"',
|
|
33
|
+
:open => "Open",
|
|
34
|
+
:open_document => '"Open Document"',
|
|
35
|
+
:openselectedhelp_about => '"Open selected help about"',
|
|
36
|
+
:reload_variables => '"Reload Variables"' ,
|
|
37
|
+
:remove_applet => '"remove applet"',
|
|
38
|
+
:return => "Return",
|
|
39
|
+
:rwdtinker_window_2 => "RwdTinker Window 2",
|
|
40
|
+
:rwdtinker => "RwdTinker",
|
|
41
|
+
:rwdtinker_back_window => '"RwdTinker Back Window"',
|
|
42
|
+
:rwdtinker_help => '"RwdTinker Help"',
|
|
43
|
+
:rwdtinker_help_window => '"RwdTinker Help Window"',
|
|
44
|
+
:showjump_links => '"Show Jump Links"',
|
|
45
|
+
:showdocument_list => '"Show Document List"',
|
|
46
|
+
:showhelpabout_links => '"Show Help About Links"',
|
|
47
|
+
|
|
48
|
+
:save => "Save" ,
|
|
49
|
+
:save_changes => '"Save Changes"',
|
|
50
|
+
:selection_panel => '"Selection Panel"',
|
|
51
|
+
:selection_tab => '"Selection Tab"',
|
|
52
|
+
:tinker_logo => "Tinker Logo",
|
|
53
|
+
:tinkerback_window => '"Tinker Back Window"',
|
|
54
|
+
:viewapplet_contents => '"View Applet Contents"',
|
|
55
|
+
:viewalreadyinstalled_applications => '"View already installed GEM applications"',
|
|
56
|
+
:viewinstalled_text => '"View Install Text"',
|
|
57
|
+
:view_platform => '"view platform"',
|
|
58
|
+
:viewplatform_information => '"View Platform Information"',
|
|
59
|
+
:view_event => '"View event"',
|
|
60
|
+
:view_gem => '"View Gem"',
|
|
61
|
+
:viewinstall_text => '"View Install Text"' ,
|
|
62
|
+
:viewlistinstall_files => '"View List of Installed Files"',
|
|
63
|
+
:view_photo => '"View Photo"',
|
|
64
|
+
:window => "Window" ,
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Japanese Language files for RwdTinker core
|
|
2
|
+
:cancel => "とりけし",
|
|
3
|
+
:open => "あける",
|
|
4
|
+
:view_event => "けんかい ぎょうじょ",
|
|
5
|
+
:edit_event => "しゅうろく",
|
|
6
|
+
:install_gem => "インストール",
|
|
7
|
+
:list_installed_gems => "かきつらねる",
|
|
8
|
+
:view_gem => "けんかい",
|
|
9
|
+
:edit => "しゅうろく",
|
|
10
|
+
:gem_commands => "コマンド",
|
|
11
|
+
:gem_files => "ファイル",
|
|
12
|
+
:gem_docs => "しょるい",
|
|
13
|
+
:gem_name => "こうもくめい",
|
|
14
|
+
:selection_panel => "せんたく",
|
|
15
|
+
:documents => "オンラインマニュアル",
|
|
16
|
+
|
|
17
|
+
# English Language files for RwdTinker core
|
|
18
|
+
|
|
19
|
+
:applet_installed => '"applet installed!"',
|
|
20
|
+
:application_version => '"Application Version"',
|
|
21
|
+
:clear => "Clear",
|
|
22
|
+
:clickfor_version => "Click for Version" ,
|
|
23
|
+
:clickbelowtoviewlistof_zip => '"click below to view lists of zips"',
|
|
24
|
+
|
|
25
|
+
:file_name => '"File Name:"',
|
|
26
|
+
:fill_record => '"Fill Record"',
|
|
27
|
+
:help => '"Help"',
|
|
28
|
+
:help_about => '"Help About"',
|
|
29
|
+
|
|
30
|
+
:install_applet => '"install (rwdtinker) applet"',
|
|
31
|
+
:jumptoapplication_location => '"Jump to Application Location"',
|
|
32
|
+
:list_applets => '"List Applets"',
|
|
33
|
+
:listappletsinthegem_directory => '"List applets in the Gem Directory"',
|
|
34
|
+
:listappletsavailablefor_installation => "List applets available for installation",
|
|
35
|
+
:list_files => '"List Files"',
|
|
36
|
+
|
|
37
|
+
:list_photos => '"List Photos"',
|
|
38
|
+
:list_zips => '"List Zips"',
|
|
39
|
+
:listzipdirappletsavailable => '"List (zip directory) applets available for installation"',
|
|
40
|
+
:menu_panel => '"Menu Panel"',
|
|
41
|
+
:module_unknown => '"Unknown Module"',
|
|
42
|
+
:next => '"Next"',
|
|
43
|
+
|
|
44
|
+
:open_document => '"Open Document"',
|
|
45
|
+
:openselectedhelp_about => '"Open selected help about"',
|
|
46
|
+
:reload_variables => '"Reload Variables"' ,
|
|
47
|
+
:remove_applet => '"remove applet"',
|
|
48
|
+
:return => "Return",
|
|
49
|
+
:rwdtinker_window_2 => "RwdTinker Window 2",
|
|
50
|
+
:rwdtinker => "RwdTinker",
|
|
51
|
+
:rwdtinker_back_window => '"RwdTinker Back Window"',
|
|
52
|
+
:rwdtinker_help => '"RwdTinker Help"',
|
|
53
|
+
:rwdtinker_help_window => '"RwdTinker Help Window"',
|
|
54
|
+
:showjump_links => '"Show Jump Links"',
|
|
55
|
+
:showdocument_list => '"Show Document List"',
|
|
56
|
+
:showhelpabout_links => '"Show Help About Links"',
|
|
57
|
+
|
|
58
|
+
:save => "Save" ,
|
|
59
|
+
:save_changes => '"Save Changes"',
|
|
60
|
+
|
|
61
|
+
:selection_tab => '"Selection Tab"',
|
|
62
|
+
:tinker_logo => "Tinker Logo",
|
|
63
|
+
:tinkerback_window => '"Tinker Back Window"',
|
|
64
|
+
:viewapplet_contents => '"View Applet Contents"',
|
|
65
|
+
:viewalreadyinstalled_applications => '"View already installed GEM applications"',
|
|
66
|
+
:viewinstalled_text => '"View Install Text"',
|
|
67
|
+
:view_platform => '"view platform"',
|
|
68
|
+
:viewplatform_information => '"View Platform Information"',
|
|
69
|
+
:viewinstall_text => '"View Install Text"' ,
|
|
70
|
+
:viewlistinstall_files => '"View List of Installed Files"',
|
|
71
|
+
:view_photo => '"View Photo"',
|
|
72
|
+
:window => "Window" ,
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# English Language files for RwdTinker core
|
|
2
|
+
|
|
3
|
+
:cancel => '"Annuleren"',
|
|
4
|
+
:open => '"Openen"',
|
|
5
|
+
:save => '"Opslaan"',
|
|
6
|
+
:window => '"Venster"',
|
|
7
|
+
:applet_installed => '"Applet geinstalleerd"',
|
|
8
|
+
:clickfor_version => '"Klier hier voor de Versie"',
|
|
9
|
+
:documents => '"Documenten"',
|
|
10
|
+
:help => '"Help"',
|
|
11
|
+
:module_unknown => '"Module onbekend"',
|
|
12
|
+
:next => '"Volgende"',
|
|
13
|
+
:rwdtinker => '"RWDTinker"',
|
|
14
|
+
:rwdtinker_help_window => '"RWDTinker Help Venster"',
|
|
15
|
+
:rwdtinker_help => '"RWDTinker Help"',
|
|
16
|
+
:rwdtinker_window_2 => '"RWDTinker Venster 2"',
|
|
17
|
+
:rwdtinker_back_window => '"RwdTinker Back Venster"',
|
|
18
|
+
:tinker_logo => '"RWDTinker Logo"',
|
|
19
|
+
:selection_panel => '"Selectie Paneel"',
|
|
20
|
+
# English Language files for RwdTinker core
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
:applet_installed => '"applet installed!"',
|
|
24
|
+
:application_version => '"Application Version"',
|
|
25
|
+
:clear => "Clear",
|
|
26
|
+
:clickfor_version => "Click for Version" ,
|
|
27
|
+
:clickbelowtoviewlistof_zip => '"click below to view lists of zips"',
|
|
28
|
+
|
|
29
|
+
:edit => "edit" ,
|
|
30
|
+
:file_name => '"File Name:"',
|
|
31
|
+
:fill_record => '"Fill Record"',
|
|
32
|
+
:help => '"Help"',
|
|
33
|
+
:help_about => '"Help About"',
|
|
34
|
+
:install_applet => '"install (rwdtinker) applet"',
|
|
35
|
+
:jumptoapplication_location => '"Jump to Application Location"',
|
|
36
|
+
:list_applets => '"List Applets"',
|
|
37
|
+
:listappletsinthegem_directory => '"List applets in the Gem Directory"',
|
|
38
|
+
:listappletsavailablefor_installation => "List applets available for installation",
|
|
39
|
+
:list_files => '"List Files"',
|
|
40
|
+
:list_installed_gems => '"List installed Gems"' ,
|
|
41
|
+
:list_photos => '"List Photos"',
|
|
42
|
+
:list_zips => '"List Zips"',
|
|
43
|
+
:listzipdirappletsavailable => '"List (zip directory) applets available for installation"',
|
|
44
|
+
:menu_panel => '"Menu Panel"',
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
:open_document => '"Open Document"',
|
|
48
|
+
:openselectedhelp_about => '"Open selected help about"',
|
|
49
|
+
:reload_variables => '"Reload Variables"' ,
|
|
50
|
+
:remove_applet => '"remove applet"',
|
|
51
|
+
:return => "Return",
|
|
52
|
+
:rwdtinker_window_2 => "RwdTinker Window 2",
|
|
53
|
+
:rwdtinker => "RwdTinker",
|
|
54
|
+
:rwdtinker_back_window => '"RwdTinker Back Window"',
|
|
55
|
+
:rwdtinker_help => '"RwdTinker Help"',
|
|
56
|
+
:rwdtinker_help_window => '"RwdTinker Help Window"',
|
|
57
|
+
:showjump_links => '"Show Jump Links"',
|
|
58
|
+
:showdocument_list => '"Show Document List"',
|
|
59
|
+
:showhelpabout_links => '"Show Help About Links"',
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
:save_changes => '"Save Changes"',
|
|
63
|
+
:selection_tab => '"Selection Tab"',
|
|
64
|
+
:tinker_logo => "Tinker Logo",
|
|
65
|
+
:tinkerback_window => '"Tinker Back Window"',
|
|
66
|
+
:viewapplet_contents => '"View Applet Contents"',
|
|
67
|
+
:viewalreadyinstalled_applications => '"View already installed GEM applications"',
|
|
68
|
+
:viewinstalled_text => '"View Install Text"',
|
|
69
|
+
:view_platform => '"view platform"',
|
|
70
|
+
:viewplatform_information => '"View Platform Information"',
|
|
71
|
+
:view_event => '"View event"',
|
|
72
|
+
:viewinstall_text => '"View Install Text"' ,
|
|
73
|
+
:viewlistinstall_files => '"View List of Installed Files"',
|
|
74
|
+
:view_photo => '"View Photo"',
|
|
75
|
+
|
data/lib/librmpd.rb
ADDED
|
@@ -0,0 +1,1152 @@
|
|
|
1
|
+
#
|
|
2
|
+
#== librmpd.rb
|
|
3
|
+
#
|
|
4
|
+
# librmpd.rb is another Ruby MPD Library with a goal of greater
|
|
5
|
+
# ease of use, more functionality, and thread safety
|
|
6
|
+
#
|
|
7
|
+
# Author:: Andrew Rader (bitwise_mcgee AT yahoo.com | http://nymb.us)
|
|
8
|
+
# Copyright:: Copyright (c) 2006 Andrew Rader
|
|
9
|
+
# License:: Distributed under the GNU GPL v2 (See COPYING file)
|
|
10
|
+
#
|
|
11
|
+
# This was written with MPD version 0.11.5 (http://www.musicpd.org)
|
|
12
|
+
#
|
|
13
|
+
# The main class is the MPD class. This provides the functionality for
|
|
14
|
+
# talking to the server as well as setting up callbacks for when events
|
|
15
|
+
# occur (such as song changes, state changes, etc). The use of callbacks
|
|
16
|
+
# is optional, if they are used a seperate thread will continuously poll
|
|
17
|
+
# the server on its status, when something is changed, your program will
|
|
18
|
+
# be notified via any callbacks you have set. Most methods are the same
|
|
19
|
+
# as specified in the MPD Server Protocol, however some have been modified
|
|
20
|
+
# or renamed. Most notable is the list* and lsinfo functions have been
|
|
21
|
+
# replace with more sane methods (such as `files` for all files)
|
|
22
|
+
#
|
|
23
|
+
#== Usage
|
|
24
|
+
#
|
|
25
|
+
# First create an MPD object
|
|
26
|
+
#
|
|
27
|
+
# require 'rubygems'
|
|
28
|
+
# require 'librmpd'
|
|
29
|
+
#
|
|
30
|
+
# mpd = MPD.new 'localhost', 6600
|
|
31
|
+
#
|
|
32
|
+
# and connect it to the server
|
|
33
|
+
#
|
|
34
|
+
# mpd.connect
|
|
35
|
+
#
|
|
36
|
+
# You can now issue any of the commands. Each command is documented below.
|
|
37
|
+
#
|
|
38
|
+
#=== Callbacks
|
|
39
|
+
#
|
|
40
|
+
# Callbacks are a way to easily setup your client as event based, rather
|
|
41
|
+
# than polling based. This means rather than having to check for changes
|
|
42
|
+
# in the server, you setup a few methods that will be called when those
|
|
43
|
+
# changes occur. For example, you could have a 'state_changed' method
|
|
44
|
+
# that will be called whenever the server changes state. You could then
|
|
45
|
+
# have this method change a label to reflect to the new state.
|
|
46
|
+
#
|
|
47
|
+
# To use callbacks in your program, first setup your callback methods. For
|
|
48
|
+
# example, say you have the class MyClient. Simply define whatever
|
|
49
|
+
# callbacks you want inside your class. See the documentation on the
|
|
50
|
+
# callback type constants in the MPD class for details on how each callback
|
|
51
|
+
# is called
|
|
52
|
+
#
|
|
53
|
+
# Once you have your callback methods defined, use the register_callback
|
|
54
|
+
# methods to inform librmpd about them. You can have multiple callbacks
|
|
55
|
+
# for each type of callback without problems. Simply use object.method('method_name')
|
|
56
|
+
# to get a reference to a Method object. Pass this object to the
|
|
57
|
+
# register_callback (along with the proper type value), and you're set.
|
|
58
|
+
#
|
|
59
|
+
# An Example:
|
|
60
|
+
#
|
|
61
|
+
# class MyClient
|
|
62
|
+
# ...
|
|
63
|
+
# def state_callback( newstate )
|
|
64
|
+
# puts "MPD Changed State: #{newstate}"
|
|
65
|
+
# end
|
|
66
|
+
# ...
|
|
67
|
+
# end
|
|
68
|
+
#
|
|
69
|
+
# client = MyClient.new
|
|
70
|
+
# mpd = MPD.new
|
|
71
|
+
# mpd.register_callback(client.method('state_callback'), MPD::STATE_CALLBACK)
|
|
72
|
+
#
|
|
73
|
+
# # Connect and Enable Callbacks
|
|
74
|
+
# mpd.connect( true )
|
|
75
|
+
#
|
|
76
|
+
# In order for the callback to be used, you must enable callbacks when you
|
|
77
|
+
# connect by passing true to the connect method. Now, whenever the state changes
|
|
78
|
+
# on the server, myclientobj's state_callback method will be called (and passed
|
|
79
|
+
# the new state as an argument)
|
|
80
|
+
|
|
81
|
+
class MPD
|
|
82
|
+
|
|
83
|
+
require 'socket'
|
|
84
|
+
require 'thread'
|
|
85
|
+
|
|
86
|
+
#
|
|
87
|
+
# These are the callback types used in registering callbacks
|
|
88
|
+
|
|
89
|
+
# STATE_CALLBACK: This is used to listen for changes in the server state
|
|
90
|
+
#
|
|
91
|
+
# The callback will always be called with a single string argument
|
|
92
|
+
# which may an empty string.
|
|
93
|
+
STATE_CALLBACK = 0
|
|
94
|
+
|
|
95
|
+
# CURRENT_SONG_CALLBACK: This is used to listen for changes in the current
|
|
96
|
+
#
|
|
97
|
+
# song being played by the server.
|
|
98
|
+
#
|
|
99
|
+
# The callback will always be called with a single argument, an MPD::Song
|
|
100
|
+
# object, or, if there were problems, nil
|
|
101
|
+
CURRENT_SONG_CALLBACK = 1
|
|
102
|
+
|
|
103
|
+
# PLAYLIST_CALLBACK: This is used to listen for when changes in the playlist
|
|
104
|
+
# are made.
|
|
105
|
+
#
|
|
106
|
+
# The callback will always be called with a single argument, an integer
|
|
107
|
+
# value for the current playlist or 0 if there were problems
|
|
108
|
+
PLAYLIST_CALLBACK = 2
|
|
109
|
+
|
|
110
|
+
# TIME_CALLBACK: This is used to listen for when the playback time changes
|
|
111
|
+
#
|
|
112
|
+
# The callback will always be called with two arguments. The first is
|
|
113
|
+
# the integer number of seconds elapsed (or 0 if errors), the second is
|
|
114
|
+
# the total number of seconds in the song (or 0 if errors)
|
|
115
|
+
TIME_CALLBACK = 3
|
|
116
|
+
|
|
117
|
+
# VOLUME_CALLBACK: This is used to listen for when the volume changes
|
|
118
|
+
#
|
|
119
|
+
# The callback will always be called with a single argument, an integer
|
|
120
|
+
# value of the volume (or 0 on errors)
|
|
121
|
+
VOLUME_CALLBACK = 4
|
|
122
|
+
|
|
123
|
+
# REPEAT_CALLBACK: This is used to listen for changes to the repeat flag
|
|
124
|
+
#
|
|
125
|
+
# The callback will always be called with a single argument, a boolean
|
|
126
|
+
# true or false depending on if the repeat flag is set / unset
|
|
127
|
+
REPEAT_CALLBACK = 5
|
|
128
|
+
|
|
129
|
+
# RANDOM_CALLBACK: This is used to listen for changed to the random flag
|
|
130
|
+
#
|
|
131
|
+
# The callback will always be called with a single argument, a boolean
|
|
132
|
+
# true or false depending on if the random flag is set / unset
|
|
133
|
+
RANDOM_CALLBACK = 6
|
|
134
|
+
|
|
135
|
+
# PLAYLIST_LENGTH_CALLBACK: This is used to listen for changes to the
|
|
136
|
+
# playlist length
|
|
137
|
+
#
|
|
138
|
+
# The callback will always be called with a single argument, an integer
|
|
139
|
+
# value of the current playlist's length (or 0 on errors)
|
|
140
|
+
PLAYLIST_LENGTH_CALLBACK = 7
|
|
141
|
+
|
|
142
|
+
# CROSSFADE_CALLBACK: This is used to listen for changes in the crossfade
|
|
143
|
+
# setting
|
|
144
|
+
#
|
|
145
|
+
# The callback will always be called with a single argument, an integer
|
|
146
|
+
# value of the number of seconds the crossfade is set to (or 0 on errsors)
|
|
147
|
+
CROSSFADE_CALLBACK = 8
|
|
148
|
+
|
|
149
|
+
# CURRENT_SONGID_CALLBACK: This is used to listen for changes in the
|
|
150
|
+
# current song's songid
|
|
151
|
+
#
|
|
152
|
+
# The callback will always be called with a single argument, an integer
|
|
153
|
+
# value of the id of the current song (or 0 on errors)
|
|
154
|
+
CURRENT_SONGID_CALLBACK = 9
|
|
155
|
+
|
|
156
|
+
# BITRATE_CALLBACK: This is used to listen for changes in the playback
|
|
157
|
+
# bitrate
|
|
158
|
+
#
|
|
159
|
+
# The callback will always be called with a single argument, an integer
|
|
160
|
+
# value of the bitrate of the playback (or 0 on errors)
|
|
161
|
+
BITRATE_CALLBACK = 10
|
|
162
|
+
|
|
163
|
+
# AUDIO_CALLBACK: This is used to listen for changes in the audio
|
|
164
|
+
# quality data (sample rate etc)
|
|
165
|
+
#
|
|
166
|
+
# The callback will always be called with three arguments, first,
|
|
167
|
+
# an integer holding the sample rate (or 0 on errors), next an
|
|
168
|
+
# integer holding the number of bits (or 0 on errors), finally an
|
|
169
|
+
# integer holding the number of channels (or 0 on errors)
|
|
170
|
+
AUDIO_CALLBACK = 11
|
|
171
|
+
|
|
172
|
+
# CONNECTION_CALLBACK: This is used to listen for changes in the
|
|
173
|
+
# connection to the server
|
|
174
|
+
#
|
|
175
|
+
# The callback will always be called with a single argument,
|
|
176
|
+
# a boolean true if the client is now connected to the server,
|
|
177
|
+
# and a boolean false if it has been disconnected
|
|
178
|
+
CONNECTION_CALLBACK = 12
|
|
179
|
+
|
|
180
|
+
#
|
|
181
|
+
#== Song
|
|
182
|
+
#
|
|
183
|
+
# This class is a glorified Hash used to represent a song
|
|
184
|
+
# You can access the various fields of a song (such as title) by
|
|
185
|
+
# either the normal hash method (song['title']) or by using
|
|
186
|
+
# the field as a method name (song.title).
|
|
187
|
+
#
|
|
188
|
+
# If the field doesn't exist or isn't set, nil will be returned
|
|
189
|
+
#
|
|
190
|
+
class Song < Hash
|
|
191
|
+
def method_missing(m, *a)
|
|
192
|
+
key = m.to_s
|
|
193
|
+
if key =~ /=$/
|
|
194
|
+
self[$`] = a[0]
|
|
195
|
+
elsif a.empty?
|
|
196
|
+
self[key]
|
|
197
|
+
else
|
|
198
|
+
raise NoMethodError, "#{m}"
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Initialize an MPD object with the specified hostname and port
|
|
204
|
+
# When called without arguments, 'localhost' and 6600 are used
|
|
205
|
+
def initialize( hostname = 'localhost', port = 6600 )
|
|
206
|
+
@hostname = hostname
|
|
207
|
+
@port = port
|
|
208
|
+
@socket = nil
|
|
209
|
+
@stop_cb_thread = false
|
|
210
|
+
@mutex = Mutex.new
|
|
211
|
+
@cb_thread = nil
|
|
212
|
+
@callbacks = []
|
|
213
|
+
@callbacks[STATE_CALLBACK] = []
|
|
214
|
+
@callbacks[CURRENT_SONG_CALLBACK] = []
|
|
215
|
+
@callbacks[PLAYLIST_CALLBACK] = []
|
|
216
|
+
@callbacks[TIME_CALLBACK] = []
|
|
217
|
+
@callbacks[VOLUME_CALLBACK] = []
|
|
218
|
+
@callbacks[REPEAT_CALLBACK] = []
|
|
219
|
+
@callbacks[RANDOM_CALLBACK] = []
|
|
220
|
+
@callbacks[PLAYLIST_LENGTH_CALLBACK] = []
|
|
221
|
+
@callbacks[CROSSFADE_CALLBACK] = []
|
|
222
|
+
@callbacks[CURRENT_SONGID_CALLBACK] = []
|
|
223
|
+
@callbacks[BITRATE_CALLBACK] = []
|
|
224
|
+
@callbacks[AUDIO_CALLBACK] = []
|
|
225
|
+
@callbacks[CONNECTION_CALLBACK] = []
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# This will store the given method onto the given type's callback
|
|
229
|
+
# list. First you must get a reference to the method to call by
|
|
230
|
+
# the following:
|
|
231
|
+
#
|
|
232
|
+
# callback_method = my_object.method 'method name'
|
|
233
|
+
#
|
|
234
|
+
# Then you can call register_callback:
|
|
235
|
+
#
|
|
236
|
+
# mpd.register_callback( callback_method, MPD::STATE_CALLBACK )
|
|
237
|
+
#
|
|
238
|
+
# Now my_object's 'method name' method will be called whenever the
|
|
239
|
+
# state changes
|
|
240
|
+
def register_callback( method, type )
|
|
241
|
+
@callbacks[type].push method
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
#
|
|
245
|
+
# Connect to the daemon
|
|
246
|
+
# When called without any arguments, this will just
|
|
247
|
+
# connect to the server and wait for your commands
|
|
248
|
+
# When called with true as an argument, this will
|
|
249
|
+
# enable callbacks by starting a seperate polling thread.
|
|
250
|
+
# This polling thread will also automatically reconnect
|
|
251
|
+
# If is disconnected for whatever reason.
|
|
252
|
+
#
|
|
253
|
+
# connect will return OK plus the version string
|
|
254
|
+
# if successful, otherwise an error will be raised
|
|
255
|
+
#
|
|
256
|
+
# If connect is called on an already connected instance,
|
|
257
|
+
# a RuntimeError is raised
|
|
258
|
+
def connect( callbacks = false )
|
|
259
|
+
if self.connected?
|
|
260
|
+
raise 'MPD Error: Already Connected'
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
@socket = TCPSocket::new @hostname, @port
|
|
264
|
+
ret = @socket.gets # Read the version
|
|
265
|
+
|
|
266
|
+
if callbacks and (@cb_thread.nil? or !@cb_thread.alive?)
|
|
267
|
+
@stop_cb_thread = false
|
|
268
|
+
@cb_thread = Thread.new( self ) { |mpd|
|
|
269
|
+
old_status = {}
|
|
270
|
+
song = ''
|
|
271
|
+
connected = ''
|
|
272
|
+
while !@stop_cb_thread
|
|
273
|
+
begin
|
|
274
|
+
status = mpd.status
|
|
275
|
+
rescue
|
|
276
|
+
status = {}
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
begin
|
|
280
|
+
c = mpd.connected?
|
|
281
|
+
rescue
|
|
282
|
+
c = false
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
if connected != c
|
|
286
|
+
connected = c
|
|
287
|
+
for cb in @callbacks[CONNECTION_CALLBACK]
|
|
288
|
+
cb.call connected
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
if old_status['time'] != status['time']
|
|
293
|
+
if old_status['time'].nil? or old_status['time'].empty?
|
|
294
|
+
old_status['time'] = '0:0'
|
|
295
|
+
end
|
|
296
|
+
t = old_status['time'].split ':'
|
|
297
|
+
elapsed = t[0].to_i
|
|
298
|
+
total = t[1].to_i
|
|
299
|
+
for cb in @callbacks[TIME_CALLBACK]
|
|
300
|
+
cb.call elapsed, total
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
if old_status['volume'] != status['volume']
|
|
305
|
+
for cb in @callbacks[VOLUME_CALLBACK]
|
|
306
|
+
cb.call status['volume'].to_i
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
if old_status['repeat'] != status['repeat']
|
|
311
|
+
for cb in @callbacks[REPEAT_CALLBACK]
|
|
312
|
+
cb.call(status['repeat'] == '1')
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
if old_status['random'] != status['random']
|
|
317
|
+
for cb in @callbacks[RANDOM_CALLBACK]
|
|
318
|
+
cb.call(status['random'] == '1')
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
if old_status['playlist'] != status['playlist']
|
|
323
|
+
for cb in @callbacks[PLAYLIST_CALLBACK]
|
|
324
|
+
cb.call status['playlist'].to_i
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
if old_status['playlistlength'] != status['playlistlength']
|
|
329
|
+
for cb in @callbacks[PLAYLIST_LENGTH_CALLBACK]
|
|
330
|
+
cb.call status['playlistlength'].to_i
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
if old_status['xfade'] != status['xfade']
|
|
335
|
+
for cb in @callbacks[CROSSFADE_CALLBACK]
|
|
336
|
+
cb.call status['xfade'].to_i
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
if old_status['state'] != status['state']
|
|
341
|
+
state = (status['state'].nil? ? '' : status['state'])
|
|
342
|
+
for cb in @callbacks[STATE_CALLBACK]
|
|
343
|
+
cb.call state
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
begin
|
|
348
|
+
s = mpd.current_song
|
|
349
|
+
rescue
|
|
350
|
+
s = nil
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
if song != s
|
|
354
|
+
song = s
|
|
355
|
+
for cb in @callbacks[CURRENT_SONG_CALLBACK]
|
|
356
|
+
cb.call song
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
if old_status['songid'] != status['songid']
|
|
361
|
+
for cb in @callbacks[CURRENT_SONGID_CALLBACK]
|
|
362
|
+
cb.call status['songid'].to_i
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
if old_status['bitrate'] != status['bitrate']
|
|
367
|
+
for cb in @callbacks[BITRATE_CALLBACK]
|
|
368
|
+
cb.call status['bitrate'].to_i
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
if old_status['audio'] != status['audio']
|
|
373
|
+
audio = (status['audio'].nil? ? '0:0:0' : status['audio'])
|
|
374
|
+
a = audio.split ':'
|
|
375
|
+
samp = a[0].to_i
|
|
376
|
+
bits = a[1].to_i
|
|
377
|
+
chans = a[2].to_i
|
|
378
|
+
for cb in @callbacks[AUDIO_CALLBACK]
|
|
379
|
+
cb.call samp, bits, chans
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
old_status = status
|
|
384
|
+
sleep 0.1
|
|
385
|
+
|
|
386
|
+
if !connected
|
|
387
|
+
sleep 2
|
|
388
|
+
begin
|
|
389
|
+
mpd.connect unless @stop_cb_thread
|
|
390
|
+
rescue
|
|
391
|
+
end
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
}
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
return ret
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
#
|
|
401
|
+
# Check if the client is connected
|
|
402
|
+
#
|
|
403
|
+
# This will return true only if the server responds
|
|
404
|
+
# otherwise false is returned
|
|
405
|
+
def connected?
|
|
406
|
+
return false if @socket.nil?
|
|
407
|
+
begin
|
|
408
|
+
ret = send_command 'ping'
|
|
409
|
+
rescue
|
|
410
|
+
ret = false
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
return ret
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
#
|
|
417
|
+
# Disconnect from the server. This has no effect
|
|
418
|
+
# if the client is not connected. Reconnect using
|
|
419
|
+
# the connect method. This will also stop the
|
|
420
|
+
# callback thread, thus disabling callbacks
|
|
421
|
+
def disconnect
|
|
422
|
+
@stop_cb_thread = true
|
|
423
|
+
|
|
424
|
+
return if @socket.nil?
|
|
425
|
+
|
|
426
|
+
@socket.puts 'close'
|
|
427
|
+
@socket.close
|
|
428
|
+
@socket = nil
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
#
|
|
432
|
+
# Add the file _path_ to the playlist. If path is a
|
|
433
|
+
# directory, it will be added recursively.
|
|
434
|
+
#
|
|
435
|
+
# Returns true if this was successful,
|
|
436
|
+
# Raises a RuntimeError if the command failed
|
|
437
|
+
def add( path )
|
|
438
|
+
send_command "add \"#{path}\""
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
#
|
|
442
|
+
# Clears the current playlist
|
|
443
|
+
#
|
|
444
|
+
# Returns true if this was successful,
|
|
445
|
+
# Raises a RuntimeError if the command failed
|
|
446
|
+
def clear
|
|
447
|
+
send_command 'clear'
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
#
|
|
451
|
+
# Clears the current error message reported in status
|
|
452
|
+
# ( This is also accomplished by any command that starts playback )
|
|
453
|
+
#
|
|
454
|
+
# Returns true if this was successful,
|
|
455
|
+
# Raises a RuntimeError if the command failed
|
|
456
|
+
def clearerror
|
|
457
|
+
send_command 'clearerror'
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
#
|
|
461
|
+
# Set the crossfade between songs in seconds
|
|
462
|
+
#
|
|
463
|
+
# Raises a RuntimeError if the command failed
|
|
464
|
+
def crossfade=( seconds )
|
|
465
|
+
send_command "crossfade #{seconds}"
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
#
|
|
469
|
+
# Read the crossfade between songs in seconds,
|
|
470
|
+
# Raises a RuntimeError if the command failed
|
|
471
|
+
def crossfade
|
|
472
|
+
status = self.status
|
|
473
|
+
return if status.nil?
|
|
474
|
+
return status['xfade'].to_i
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
#
|
|
478
|
+
# Read the currently playing song
|
|
479
|
+
#
|
|
480
|
+
# Returns a Song object with the current song's data,
|
|
481
|
+
# Raises a RuntimeError if the command failed
|
|
482
|
+
def current_song
|
|
483
|
+
build_song( send_command('currentsong') )
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
#
|
|
487
|
+
# Delete the song from the playlist, where pos
|
|
488
|
+
# is the song's position in the playlist
|
|
489
|
+
#
|
|
490
|
+
# Returns true if successful,
|
|
491
|
+
# Raises a RuntimeError if the command failed
|
|
492
|
+
def delete( pos )
|
|
493
|
+
send_command "delete #{pos}"
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
#
|
|
497
|
+
# Delete the song with the songid from the playlist
|
|
498
|
+
#
|
|
499
|
+
# Returns true if successful,
|
|
500
|
+
# Raises a RuntimeError if the command failed
|
|
501
|
+
def deleteid( songid )
|
|
502
|
+
send_command "deleteid #{songid}"
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
#
|
|
506
|
+
# Finds songs in the database that are EXACTLY
|
|
507
|
+
# matched by the what argument. type should be
|
|
508
|
+
# 'album', 'artist', or 'title'
|
|
509
|
+
#
|
|
510
|
+
# This returns an Array of MPD::Songs,
|
|
511
|
+
# Raises a RuntimeError if the command failed
|
|
512
|
+
def find( type, what )
|
|
513
|
+
response = send_command "find \"#{type}\" \"#{what}\""
|
|
514
|
+
build_songs_list response
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
#
|
|
518
|
+
# Kills MPD
|
|
519
|
+
#
|
|
520
|
+
# Returns true if successful.
|
|
521
|
+
# Raises a RuntimeError if the command failed
|
|
522
|
+
def kill
|
|
523
|
+
send_command 'kill'
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
#
|
|
527
|
+
# Lists all of the albums in the database
|
|
528
|
+
# The optional argument is for specifying an
|
|
529
|
+
# artist to list the albums for
|
|
530
|
+
#
|
|
531
|
+
# Returns an Array of Album names (Strings),
|
|
532
|
+
# Raises a RuntimeError if the command failed
|
|
533
|
+
def albums( artist = nil )
|
|
534
|
+
list 'album', artist
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
#
|
|
538
|
+
# Lists all of the artists in the database
|
|
539
|
+
#
|
|
540
|
+
# Returns an Array of Artist names (Strings),
|
|
541
|
+
# Raises a RuntimeError if the command failed
|
|
542
|
+
def artists
|
|
543
|
+
list 'artist'
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
#
|
|
547
|
+
# This is used by the albums and artists methods
|
|
548
|
+
# type should be 'album' or 'artist'. If type is 'album'
|
|
549
|
+
# then arg can be a specific artist to list the albums for
|
|
550
|
+
#
|
|
551
|
+
# Returns an Array of Strings,
|
|
552
|
+
# Raises a RuntimeError if the command failed
|
|
553
|
+
def list( type, arg = nil )
|
|
554
|
+
if not arg.nil?
|
|
555
|
+
response = send_command "list #{type} \"#{arg}\""
|
|
556
|
+
else
|
|
557
|
+
response = send_command "list #{type}"
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
list = []
|
|
561
|
+
if not response.nil? and response.kind_of? String
|
|
562
|
+
lines = response.split "\n"
|
|
563
|
+
re = Regexp.new "\\A#{type}: ", 'i'
|
|
564
|
+
for line in lines
|
|
565
|
+
list << line.gsub( re, '' )
|
|
566
|
+
end
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
return list
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
#
|
|
573
|
+
# List all of the directories in the database, starting at path.
|
|
574
|
+
# If path isn't specified, the root of the database is used
|
|
575
|
+
#
|
|
576
|
+
# Returns an Array of directory names (Strings),
|
|
577
|
+
# Raises a RuntimeError if the command failed
|
|
578
|
+
def directories( path = nil )
|
|
579
|
+
if not path.nil?
|
|
580
|
+
response = send_command "listall \"#{path}\""
|
|
581
|
+
else
|
|
582
|
+
response = send_command 'listall'
|
|
583
|
+
end
|
|
584
|
+
|
|
585
|
+
filter_response response, /\Adirectory: /i
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
#
|
|
589
|
+
# List all of the files in the database, starting at path.
|
|
590
|
+
# If path isn't specified, the root of the database is used
|
|
591
|
+
#
|
|
592
|
+
# Returns an Array of file names (Strings).
|
|
593
|
+
# Raises a RuntimeError if the command failed
|
|
594
|
+
def files( path = nil )
|
|
595
|
+
if not path.nil?
|
|
596
|
+
response = send_command "listall \"#{path}\""
|
|
597
|
+
else
|
|
598
|
+
response = send_command 'listall'
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
filter_response response, /\Afile: /i
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
#
|
|
605
|
+
# List all of the playlists in the database
|
|
606
|
+
#
|
|
607
|
+
# Returns an Array of playlist names (Strings)
|
|
608
|
+
def playlists
|
|
609
|
+
response = send_command 'lsinfo'
|
|
610
|
+
|
|
611
|
+
filter_response response, /\Aplaylist: /i
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
#
|
|
615
|
+
# List all of the songs in the database starting at path.
|
|
616
|
+
# If path isn't specified, the root of the database is used
|
|
617
|
+
#
|
|
618
|
+
# Returns an Array of MPD::Songs,
|
|
619
|
+
# Raises a RuntimeError if the command failed
|
|
620
|
+
def songs( path = nil )
|
|
621
|
+
if not path.nil?
|
|
622
|
+
response = send_command "listallinfo \"#{path}\""
|
|
623
|
+
else
|
|
624
|
+
response = send_command 'listallinfo'
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
build_songs_list response
|
|
628
|
+
end
|
|
629
|
+
|
|
630
|
+
#
|
|
631
|
+
# List all of the songs by an artist
|
|
632
|
+
#
|
|
633
|
+
# Returns an Array of MPD::Songs by the artist `artist`,
|
|
634
|
+
# Raises a RuntimeError if the command failed
|
|
635
|
+
def songs_by_artist( artist )
|
|
636
|
+
all_songs = self.songs
|
|
637
|
+
artist_songs = []
|
|
638
|
+
all_songs.each do |song|
|
|
639
|
+
if song.artist == artist
|
|
640
|
+
artist_songs << song
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
return artist_songs
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
#
|
|
648
|
+
# Loads the playlist name.m3u (do not pass the m3u extension
|
|
649
|
+
# when calling) from the playlist directory. Use `playlists`
|
|
650
|
+
# to what playlists are available
|
|
651
|
+
#
|
|
652
|
+
# Returns true if successful,
|
|
653
|
+
# Raises a RuntimeError if the command failed
|
|
654
|
+
def load( name )
|
|
655
|
+
send_command "load \"#{name}\""
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
#
|
|
659
|
+
# Move the song at `from` to `to` in the playlist
|
|
660
|
+
#
|
|
661
|
+
# Returns true if successful,
|
|
662
|
+
# Raises a RuntimeError if the command failed
|
|
663
|
+
def move( from, to )
|
|
664
|
+
send_command "move #{from} #{to}"
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
#
|
|
668
|
+
# Move the song with the `songid` to `to` in the playlist
|
|
669
|
+
#
|
|
670
|
+
# Returns true if successful,
|
|
671
|
+
# Raises a RuntimeError if the command failed
|
|
672
|
+
def moveid( songid, to )
|
|
673
|
+
send_command "moveid #{songid} #{to}"
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
#
|
|
677
|
+
# Plays the next song in the playlist
|
|
678
|
+
#
|
|
679
|
+
# Returns true if successful,
|
|
680
|
+
# Raises a RuntimeError if the command failed
|
|
681
|
+
def next
|
|
682
|
+
send_command 'next'
|
|
683
|
+
end
|
|
684
|
+
|
|
685
|
+
#
|
|
686
|
+
# Set / Unset paused playback
|
|
687
|
+
#
|
|
688
|
+
# Returns true if successful,
|
|
689
|
+
# Raises a RuntimeError if the command failed
|
|
690
|
+
def pause=( toggle )
|
|
691
|
+
send_command 'pause ' + (toggle ? '1' : '0')
|
|
692
|
+
end
|
|
693
|
+
|
|
694
|
+
#
|
|
695
|
+
# Returns true if MPD is paused,
|
|
696
|
+
# Raises a RuntimeError if the command failed
|
|
697
|
+
def paused?
|
|
698
|
+
status = self.status
|
|
699
|
+
return false if status.nil?
|
|
700
|
+
return status['state'] == 'pause'
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
#
|
|
704
|
+
# This is used for authentication with the server
|
|
705
|
+
# `pass` is simply the plaintext password
|
|
706
|
+
#
|
|
707
|
+
# Raises a RuntimeError if the command failed
|
|
708
|
+
def password( pass )
|
|
709
|
+
send_command "password \"#{pass}\""
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
#
|
|
713
|
+
# Ping the server
|
|
714
|
+
#
|
|
715
|
+
# Returns true if successful,
|
|
716
|
+
# Raises a RuntimeError if the command failed
|
|
717
|
+
def ping
|
|
718
|
+
send_command 'ping'
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
#
|
|
722
|
+
# Begin playing the playist. Optionally
|
|
723
|
+
# specify the pos to start on
|
|
724
|
+
#
|
|
725
|
+
# Returns true if successful,
|
|
726
|
+
# Raises a RuntimeError if the command failed
|
|
727
|
+
def play( pos = nil )
|
|
728
|
+
if pos.nil?
|
|
729
|
+
return send_command('play')
|
|
730
|
+
else
|
|
731
|
+
return send_command("play #{pos}")
|
|
732
|
+
end
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
#
|
|
736
|
+
# Returns true if the server's state is set to 'play',
|
|
737
|
+
# Raises a RuntimeError if the command failed
|
|
738
|
+
def playing?
|
|
739
|
+
state = self.status['state']
|
|
740
|
+
return state == 'play'
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
#
|
|
744
|
+
# Begin playing the playlist. Optionally
|
|
745
|
+
# specify the songid to start on
|
|
746
|
+
#
|
|
747
|
+
# Returns true if successful,
|
|
748
|
+
# Raises a RuntimeError if the command failed
|
|
749
|
+
def playid( songid = nil )
|
|
750
|
+
if not songid.nil?
|
|
751
|
+
return(send_command("playid #{songid}"))
|
|
752
|
+
else
|
|
753
|
+
return(send_command('playid'))
|
|
754
|
+
end
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
#
|
|
758
|
+
# Returns the current playlist version number,
|
|
759
|
+
# Raises a RuntimeError if the command failed
|
|
760
|
+
def playlist_version
|
|
761
|
+
self.status['playlist'].to_i
|
|
762
|
+
end
|
|
763
|
+
|
|
764
|
+
#
|
|
765
|
+
# List the current playlist
|
|
766
|
+
# This is the same as playlistinfo w/o args
|
|
767
|
+
#
|
|
768
|
+
# Returns an Array of MPD::Songs,
|
|
769
|
+
# Raises a RuntimeError if the command failed
|
|
770
|
+
def playlist
|
|
771
|
+
response = send_command 'playlistinfo'
|
|
772
|
+
build_songs_list response
|
|
773
|
+
end
|
|
774
|
+
|
|
775
|
+
#
|
|
776
|
+
# Returns the MPD::Song at the position `pos` in the playlist,
|
|
777
|
+
# Raises a RuntimeError if the command failed
|
|
778
|
+
def song_at_pos( pos )
|
|
779
|
+
build_song( send_command("playlistinfo #{pos}") )
|
|
780
|
+
end
|
|
781
|
+
|
|
782
|
+
#
|
|
783
|
+
# Returns the MPD::Song with the `songid` in the playlist,
|
|
784
|
+
# Raises a RuntimeError if the command failed
|
|
785
|
+
def song_with_id( songid )
|
|
786
|
+
build_song( send_command("playlistid #{songid}") )
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
#
|
|
790
|
+
# List the changes since the specified version in the playlist
|
|
791
|
+
#
|
|
792
|
+
# Returns an Array of MPD::Songs,
|
|
793
|
+
# Raises a RuntimeError if the command failed
|
|
794
|
+
def playlist_changes( version )
|
|
795
|
+
response = send_command "plchanges #{version}"
|
|
796
|
+
build_songs_list response
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
#
|
|
800
|
+
# Plays the previous song in the playlist
|
|
801
|
+
#
|
|
802
|
+
# Returns true if successful,
|
|
803
|
+
# Raises a RuntimeError if the command failed
|
|
804
|
+
def previous
|
|
805
|
+
send_command 'previous'
|
|
806
|
+
end
|
|
807
|
+
|
|
808
|
+
#
|
|
809
|
+
# Enable / Disable random playback,
|
|
810
|
+
# Raises a RuntimeError if the command failed
|
|
811
|
+
def random=( toggle )
|
|
812
|
+
send_command 'random ' + (toggle ? '1' : '0')
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
#
|
|
816
|
+
# Returns true if random playback is currently enabled,
|
|
817
|
+
# Raises a RuntimeError if the command failed
|
|
818
|
+
def random?
|
|
819
|
+
rand = self.status['random']
|
|
820
|
+
return rand == '1'
|
|
821
|
+
end
|
|
822
|
+
|
|
823
|
+
#
|
|
824
|
+
# Enable / Disable repeat,
|
|
825
|
+
# Raises a RuntimeError if the command failed
|
|
826
|
+
def repeat=( toggle )
|
|
827
|
+
send_command 'repeat ' + (toggle ? '1' : '0')
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
#
|
|
831
|
+
# Returns true if repeat is enabled,
|
|
832
|
+
# Raises a RuntimeError if the command failed
|
|
833
|
+
def repeat?
|
|
834
|
+
repeat = self.status['repeat']
|
|
835
|
+
return repeat == '1'
|
|
836
|
+
end
|
|
837
|
+
|
|
838
|
+
#
|
|
839
|
+
# Removes (PERMANENTLY!) the playlist `playlist.m3u` from
|
|
840
|
+
# the playlist directory
|
|
841
|
+
#
|
|
842
|
+
# Returns true if successful,
|
|
843
|
+
# Raises a RuntimeError if the command failed
|
|
844
|
+
def rm( playlist )
|
|
845
|
+
send_command "rm \"#{playlist}\""
|
|
846
|
+
end
|
|
847
|
+
|
|
848
|
+
#
|
|
849
|
+
# An Alias for rm
|
|
850
|
+
def remove_playlist( playlist )
|
|
851
|
+
rm playlist
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
#
|
|
855
|
+
# Saves the current playlist to `playlist`.m3u in the
|
|
856
|
+
# playlist directory
|
|
857
|
+
#
|
|
858
|
+
# Returns true if successful,
|
|
859
|
+
# Raises a RuntimeError if the command failed
|
|
860
|
+
def save( playlist )
|
|
861
|
+
send_command "save \"#{playlist}\""
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
#
|
|
865
|
+
# Searches for any song that contains `what` in the `type` field
|
|
866
|
+
# `type` can be 'title', 'artist', 'album' or 'filename'
|
|
867
|
+
# Searches are NOT case sensitive
|
|
868
|
+
#
|
|
869
|
+
# Returns an Array of MPD::Songs,
|
|
870
|
+
# Raises a RuntimeError if the command failed
|
|
871
|
+
def search( type, what )
|
|
872
|
+
build_songs_list( send_command("search #{type} \"#{what}\"") )
|
|
873
|
+
end
|
|
874
|
+
|
|
875
|
+
#
|
|
876
|
+
# Seeks to the position `time` (in seconds) of the
|
|
877
|
+
# song at `pos` in the playlist
|
|
878
|
+
#
|
|
879
|
+
# Returns true if successful,
|
|
880
|
+
# Raises a RuntimeError if the command failed
|
|
881
|
+
def seek( pos, time )
|
|
882
|
+
send_command "seek #{pos} #{time}"
|
|
883
|
+
end
|
|
884
|
+
|
|
885
|
+
#
|
|
886
|
+
# Seeks to the position `time` (in seconds) of the song with
|
|
887
|
+
# the id `songid`
|
|
888
|
+
#
|
|
889
|
+
# Returns true if successful,
|
|
890
|
+
# Raises a RuntimeError if the command failed
|
|
891
|
+
def seekid( songid, time )
|
|
892
|
+
send_command "seekid #{songid} #{time}"
|
|
893
|
+
end
|
|
894
|
+
|
|
895
|
+
#
|
|
896
|
+
# Set the volume
|
|
897
|
+
# The argument `vol` will automatically be bounded to 0 - 100
|
|
898
|
+
#
|
|
899
|
+
# Raises a RuntimeError if the command failed
|
|
900
|
+
def volume=( vol )
|
|
901
|
+
send_command "setvol #{vol}"
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
#
|
|
905
|
+
# Returns the volume,
|
|
906
|
+
# Raises a RuntimeError if the command failed
|
|
907
|
+
def volume
|
|
908
|
+
status = self.status
|
|
909
|
+
return if status.nil?
|
|
910
|
+
return status['volume'].to_i
|
|
911
|
+
end
|
|
912
|
+
|
|
913
|
+
#
|
|
914
|
+
# Shuffles the playlist,
|
|
915
|
+
# Raises a RuntimeError if the command failed
|
|
916
|
+
def shuffle
|
|
917
|
+
send_command 'shuffle'
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
#
|
|
921
|
+
# Returns a Hash of MPD's stats,
|
|
922
|
+
# Raises a RuntimeError if the command failed
|
|
923
|
+
def stats
|
|
924
|
+
response = send_command 'stats'
|
|
925
|
+
build_hash response
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
#
|
|
929
|
+
# Returns a Hash of the current status,
|
|
930
|
+
# Raises a RuntimeError if the command failed
|
|
931
|
+
def status
|
|
932
|
+
response = send_command 'status'
|
|
933
|
+
build_hash response
|
|
934
|
+
end
|
|
935
|
+
|
|
936
|
+
#
|
|
937
|
+
# Stop playing
|
|
938
|
+
#
|
|
939
|
+
# Returns true if successful,
|
|
940
|
+
# Raises a RuntimeError if the command failed
|
|
941
|
+
def stop
|
|
942
|
+
send_command 'stop'
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
#
|
|
946
|
+
# Returns true if the server's state is 'stop',
|
|
947
|
+
# Raises a RuntimeError if the command failed
|
|
948
|
+
def stopped?
|
|
949
|
+
status = self.status
|
|
950
|
+
return false if status.nil?
|
|
951
|
+
return status['state'] == 'stop'
|
|
952
|
+
end
|
|
953
|
+
|
|
954
|
+
#
|
|
955
|
+
# Swaps the song at position `posA` with the song
|
|
956
|
+
# as position `posB` in the playlist
|
|
957
|
+
#
|
|
958
|
+
# Returns true if successful,
|
|
959
|
+
# Raises a RuntimeError if the command failed
|
|
960
|
+
def swap( posA, posB )
|
|
961
|
+
send_command "swap #{posA} #{posB}"
|
|
962
|
+
end
|
|
963
|
+
|
|
964
|
+
#
|
|
965
|
+
# Swaps the song with the id `songidA` with the song
|
|
966
|
+
# with the id `songidB`
|
|
967
|
+
#
|
|
968
|
+
# Returns true if successful,
|
|
969
|
+
# Raises a RuntimeError if the command failed
|
|
970
|
+
def swapid( songidA, songidB )
|
|
971
|
+
send_command "swapid #{songidA} #{songidB}"
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
#
|
|
975
|
+
# Tell the server to update the database. Optionally,
|
|
976
|
+
# specify the path to update
|
|
977
|
+
def update( path = nil )
|
|
978
|
+
ret = ''
|
|
979
|
+
if not path.nil?
|
|
980
|
+
ret = send_command("update \"#{path}\"")
|
|
981
|
+
else
|
|
982
|
+
ret = send_command('update')
|
|
983
|
+
end
|
|
984
|
+
|
|
985
|
+
return(ret.gsub('updating_db: ', '').to_i)
|
|
986
|
+
end
|
|
987
|
+
|
|
988
|
+
#
|
|
989
|
+
# Private Method
|
|
990
|
+
#
|
|
991
|
+
# Used to send a command to the server. This synchronizes
|
|
992
|
+
# on a mutex to be thread safe
|
|
993
|
+
#
|
|
994
|
+
# Returns the server response as processed by `handle_server_response`,
|
|
995
|
+
# Raises a RuntimeError if the command failed
|
|
996
|
+
def send_command( command )
|
|
997
|
+
if @socket.nil?
|
|
998
|
+
raise "MPD: Not Connected to the Server"
|
|
999
|
+
end
|
|
1000
|
+
|
|
1001
|
+
ret = nil
|
|
1002
|
+
|
|
1003
|
+
@mutex.synchronize do
|
|
1004
|
+
begin
|
|
1005
|
+
@socket.puts command
|
|
1006
|
+
ret = handle_server_response
|
|
1007
|
+
rescue Errno::EPIPE
|
|
1008
|
+
@socket = nil
|
|
1009
|
+
raise 'MPD Error: Broken Pipe (Disconnected)'
|
|
1010
|
+
end
|
|
1011
|
+
end
|
|
1012
|
+
|
|
1013
|
+
return ret
|
|
1014
|
+
end
|
|
1015
|
+
|
|
1016
|
+
#
|
|
1017
|
+
# Private Method
|
|
1018
|
+
#
|
|
1019
|
+
# Handles the server's response (called inside send_command)
|
|
1020
|
+
#
|
|
1021
|
+
# This will repeatedly read the server's response from the socket
|
|
1022
|
+
# and will process the output. If a string is returned by the server
|
|
1023
|
+
# that is what is returned. If just an "OK" is returned, this returns
|
|
1024
|
+
# true. If an "ACK" is returned, this raises an error
|
|
1025
|
+
def handle_server_response
|
|
1026
|
+
return if @socket.nil?
|
|
1027
|
+
|
|
1028
|
+
msg = ''
|
|
1029
|
+
reading = true
|
|
1030
|
+
error = nil
|
|
1031
|
+
while reading
|
|
1032
|
+
line = @socket.gets
|
|
1033
|
+
case line
|
|
1034
|
+
when "OK\n"
|
|
1035
|
+
reading = false
|
|
1036
|
+
when /^ACK/
|
|
1037
|
+
error = line
|
|
1038
|
+
reading = false
|
|
1039
|
+
when nil
|
|
1040
|
+
reading = false
|
|
1041
|
+
else
|
|
1042
|
+
msg += line
|
|
1043
|
+
end
|
|
1044
|
+
end
|
|
1045
|
+
|
|
1046
|
+
if error.nil?
|
|
1047
|
+
return true if msg.empty?
|
|
1048
|
+
return msg
|
|
1049
|
+
else
|
|
1050
|
+
raise error.gsub( /^ACK \[(\d+)\@(\d+)\] \{(.+)\} (.+)$/, 'MPD Error #\1: \3: \4')
|
|
1051
|
+
end
|
|
1052
|
+
end
|
|
1053
|
+
|
|
1054
|
+
#
|
|
1055
|
+
# Private Method
|
|
1056
|
+
#
|
|
1057
|
+
# This builds a hash out of lines returned from the server.
|
|
1058
|
+
# First the response is turned into an array of lines
|
|
1059
|
+
# then each entry is parsed so that the line is viewed as
|
|
1060
|
+
# "key: value"
|
|
1061
|
+
#
|
|
1062
|
+
# The end result is a hash containing the proper key/value pairs
|
|
1063
|
+
def build_hash( string )
|
|
1064
|
+
return {} if string.nil? or !string.kind_of? String
|
|
1065
|
+
|
|
1066
|
+
hash = {}
|
|
1067
|
+
lines = string.split "\n"
|
|
1068
|
+
lines.each do |line|
|
|
1069
|
+
hash[ line.gsub(/:.*/, '').downcase ] = line.gsub(/\A[^:]*: /, '')
|
|
1070
|
+
end
|
|
1071
|
+
|
|
1072
|
+
return hash
|
|
1073
|
+
end
|
|
1074
|
+
|
|
1075
|
+
#
|
|
1076
|
+
# Private Method
|
|
1077
|
+
#
|
|
1078
|
+
# This is similar to build_hash, but instead of building a Hash,
|
|
1079
|
+
# a MPD::Song is built
|
|
1080
|
+
def build_song( string )
|
|
1081
|
+
return if string.nil? or !string.kind_of? String
|
|
1082
|
+
|
|
1083
|
+
song = Song.new
|
|
1084
|
+
lines = string.split "\n"
|
|
1085
|
+
lines.each do |line|
|
|
1086
|
+
song[ line.gsub(/:.*/, '').downcase ] = line.gsub(/\A[^:]*: /, '')
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
return song
|
|
1090
|
+
end
|
|
1091
|
+
|
|
1092
|
+
#
|
|
1093
|
+
# Private Method
|
|
1094
|
+
#
|
|
1095
|
+
# This first creates an array of lines as returned from the server
|
|
1096
|
+
# Then each entry is processed and added to an MPD::Song
|
|
1097
|
+
# Whenever a new 'file:' entry is found, the current MPD::Song
|
|
1098
|
+
# is added to an array, and a new one is created
|
|
1099
|
+
#
|
|
1100
|
+
# The end result is an Array of MPD::Songs
|
|
1101
|
+
def build_songs_list( string )
|
|
1102
|
+
return [] if string.nil? or !string.kind_of? String
|
|
1103
|
+
|
|
1104
|
+
list = []
|
|
1105
|
+
song = Song.new
|
|
1106
|
+
lines = string.split "\n"
|
|
1107
|
+
lines.each do |line|
|
|
1108
|
+
key = line.gsub(/:.*/, '')
|
|
1109
|
+
line.gsub!(/\A[^:]*: /, '')
|
|
1110
|
+
|
|
1111
|
+
if key == 'file' && !song.file.nil?
|
|
1112
|
+
list << song
|
|
1113
|
+
song = Song.new
|
|
1114
|
+
end
|
|
1115
|
+
|
|
1116
|
+
song[key.downcase] = line
|
|
1117
|
+
end
|
|
1118
|
+
|
|
1119
|
+
list << song
|
|
1120
|
+
|
|
1121
|
+
return list
|
|
1122
|
+
end
|
|
1123
|
+
|
|
1124
|
+
#
|
|
1125
|
+
# Private Method
|
|
1126
|
+
#
|
|
1127
|
+
# This filters each line from the server to return
|
|
1128
|
+
# only those matching the regexp. The regexp is removed
|
|
1129
|
+
# from the line before it is added to an Array
|
|
1130
|
+
#
|
|
1131
|
+
# This is used in the `directories`, `files`, etc methods
|
|
1132
|
+
# to return only the directory/file names
|
|
1133
|
+
def filter_response( string, regexp )
|
|
1134
|
+
list = []
|
|
1135
|
+
lines = string.split "\n"
|
|
1136
|
+
lines.each do |line|
|
|
1137
|
+
if line =~ regexp
|
|
1138
|
+
list << line.gsub(regexp, '')
|
|
1139
|
+
end
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
return list
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
private :send_command
|
|
1146
|
+
private :handle_server_response
|
|
1147
|
+
private :build_hash
|
|
1148
|
+
private :build_song
|
|
1149
|
+
private :build_songs_list
|
|
1150
|
+
private :filter_response
|
|
1151
|
+
|
|
1152
|
+
end
|