rwdmpd 0.06

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. data/Readme.txt +475 -0
  2. data/bin/rwdmpd +19 -0
  3. data/code/01rwdcore/01rwdcore.rb +29 -0
  4. data/code/01rwdcore/02helptexthashbegin.rb +4 -0
  5. data/code/01rwdcore/03helptexthash.rb +23 -0
  6. data/code/01rwdcore/04helptextend.rb +6 -0
  7. data/code/01rwdcore/jumplinkcommand.rb +26 -0
  8. data/code/01rwdcore/openhelpwindow.rb +31 -0
  9. data/code/01rwdcore/returntomain.rb +10 -0
  10. data/code/01rwdcore/rundocuments.rb +10 -0
  11. data/code/01rwdcore/runeditconfiguration.rb +10 -0
  12. data/code/01rwdcore/runhelpabout.rb +10 -0
  13. data/code/01rwdcore/runopentinkerdocument.rb +7 -0
  14. data/code/01rwdcore/rwdtinkerversion.rb +22 -0
  15. data/code/01rwdcore/rwdwindowreturn.rb +9 -0
  16. data/code/01rwdcore/selectiontab.rb +9 -0
  17. data/code/01rwdcore/setuphelpaboutoptions.rb +13 -0
  18. data/code/01rwdcore/setuptinkerdocuments.rb +6 -0
  19. data/code/01rwdcore/test_cases.rb +109 -0
  20. data/code/01rwdcore/test_harness.rb +13 -0
  21. data/code/01rwdcore/uploadreturns.rb +62 -0
  22. data/code/dd0viewphoto/dd0viewphoto.rb +3 -0
  23. data/code/superant.com.rwdmp3/0uninstallapplet.rb +11 -0
  24. data/code/superant.com.rwdmp3/clearscreendisplay.rb +7 -0
  25. data/code/superant.com.rwdmp3/controlmpd.rb +139 -0
  26. data/code/superant.com.rwdmp3/helptexthashrwdmp3.rb +41 -0
  27. data/code/superant.com.rwdmp3/listplaylistfiles.rb +12 -0
  28. data/code/superant.com.rwdmp3/loadconfigurationrecord.rb +22 -0
  29. data/code/superant.com.rwdmp3/loadconfigurationvariables.rb +13 -0
  30. data/code/superant.com.rwdmp3/loadplaylistrecord.rb +19 -0
  31. data/code/superant.com.rwdmp3/mpd_client.rb +41 -0
  32. data/code/superant.com.rwdmp3/mpd_seek.rb +23 -0
  33. data/code/superant.com.rwdmp3/openhelpwindowrwdmp3.rb +25 -0
  34. data/code/superant.com.rwdmp3/runrwdmpdwindow.rb +10 -0
  35. data/code/superant.com.rwdmp3/rwdtinkerversion.rb +10 -0
  36. data/code/superant.com.rwdmp3/saveconfigurationrecord.rb +19 -0
  37. data/code/superant.com.rwdmp3/saveplaylistrecord.rb +18 -0
  38. data/code/superant.com.rwdmp3/startmp3server.rb +16 -0
  39. data/code/superant.com.rwdtinkerbackwindow/diagnostictab.rb +19 -0
  40. data/code/superant.com.rwdtinkerbackwindow/helptexthashtinkerwin2.rb +61 -0
  41. data/code/superant.com.rwdtinkerbackwindow/initiateapplets.rb +240 -0
  42. data/code/superant.com.rwdtinkerbackwindow/installgemapplet.rb +34 -0
  43. data/code/superant.com.rwdtinkerbackwindow/installremotegem.rb +20 -0
  44. data/code/superant.com.rwdtinkerbackwindow/listgemdirs.rb +12 -0
  45. data/code/superant.com.rwdtinkerbackwindow/listgemzips.rb +53 -0
  46. data/code/superant.com.rwdtinkerbackwindow/listinstalledfiles.rb +12 -0
  47. data/code/superant.com.rwdtinkerbackwindow/listzips.rb +33 -0
  48. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationrecord.rb +22 -0
  49. data/code/superant.com.rwdtinkerbackwindow/loadconfigurationvariables.rb +14 -0
  50. data/code/superant.com.rwdtinkerbackwindow/network.rb +87 -0
  51. data/code/superant.com.rwdtinkerbackwindow/openappletname.rb +19 -0
  52. data/code/superant.com.rwdtinkerbackwindow/openhelpwindowtinkerwin2.rb +38 -0
  53. data/code/superant.com.rwdtinkerbackwindow/remotegemlist.rb +24 -0
  54. data/code/superant.com.rwdtinkerbackwindow/removeapplet.rb +46 -0
  55. data/code/superant.com.rwdtinkerbackwindow/removeappletvariables.rb +52 -0
  56. data/code/superant.com.rwdtinkerbackwindow/runremoteinstall.rb +11 -0
  57. data/code/superant.com.rwdtinkerbackwindow/runrwdtinkerbackwindow.rb +15 -0
  58. data/code/superant.com.rwdtinkerbackwindow/rwdtinkerwin2version.rb +13 -0
  59. data/code/superant.com.rwdtinkerbackwindow/saveconfigurationrecord.rb +19 -0
  60. data/code/superant.com.rwdtinkerbackwindow/viewappletcontents.rb +22 -0
  61. data/code/superant.com.rwdtinkerbackwindow/viewgemappletcontents.rb +24 -0
  62. data/code/zz0applicationend/zz0end.rb +4 -0
  63. data/configuration/language.dist +8 -0
  64. data/configuration/rwdapplicationidentity.dist +3 -0
  65. data/configuration/rwdtinker.dist +15 -0
  66. data/configuration/rwdwmpd-0.06.dist +14 -0
  67. data/configuration/tinkerwin2variables.dist +18 -0
  68. data/gui/00coreguibegin/applicationguitop.rwd +4 -0
  69. data/gui/frontwindow0/cc0openphoto.rwd +22 -0
  70. data/gui/frontwindowselections/00selectiontabbegin.rwd +11 -0
  71. data/gui/frontwindowselections/jumplinkcommands.rwd +15 -0
  72. data/gui/frontwindowselections/wwselectionend.rwd +3 -0
  73. data/gui/frontwindowtdocuments/00documentbegin.rwd +6 -0
  74. data/gui/frontwindowtdocuments/tinkerdocuments.rwd +14 -0
  75. data/gui/frontwindowtdocuments/zzdocumentend.rwd +8 -0
  76. data/gui/helpaboutbegin/zzzrwdlasttab.rwd +6 -0
  77. data/gui/helpaboutbegin/zzzzhelpscreenstart.rwd +3 -0
  78. data/gui/helpaboutbegin/zzzzzzhelpabouttab.rwd +15 -0
  79. data/gui/helpaboutzend/helpscreenend.rwd +3 -0
  80. data/gui/helpaboutzend/zhelpscreenstart2.rwd +3 -0
  81. data/gui/helpaboutzend/zzzzhelpabout2.rwd +15 -0
  82. data/gui/helpaboutzend/zzzzhelpscreen2end.rwd +3 -0
  83. data/gui/tinkerbackwindows/superant.com.rwdmp3/10appletbegin.rwd +4 -0
  84. data/gui/tinkerbackwindows/superant.com.rwdmp3/20rwdmpd.rwd +37 -0
  85. data/gui/tinkerbackwindows/superant.com.rwdmp3/25rwdseek.rwd +23 -0
  86. data/gui/tinkerbackwindows/superant.com.rwdmp3/30editplaylist.rwd +27 -0
  87. data/gui/tinkerbackwindows/superant.com.rwdmp3/88viewconfiguration.rwd +32 -0
  88. data/gui/tinkerbackwindows/superant.com.rwdmp3/89rwddiagnostics.rwd +26 -0
  89. data/gui/tinkerbackwindows/superant.com.rwdmp3/90jumplinkcommands.rwd +17 -0
  90. data/gui/tinkerbackwindows/superant.com.rwdmp3/9end.rwd +6 -0
  91. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/1appname.rwd +5 -0
  92. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/40rwdlistzips.rwd +41 -0
  93. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/45installremotezip.rwd +44 -0
  94. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/50rwdlistapplets.rwd +44 -0
  95. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/60editconfiguration.rwd +30 -0
  96. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/70rwddiagnostics.rwd +29 -0
  97. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/81jumplinkcommands.rwd +17 -0
  98. data/gui/tinkerbackwindows/superant.com.tinkerbackwindow/9backend.rwd +6 -0
  99. data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/1appname.rwd +31 -0
  100. data/gui/tinkerbackwindows/superant.com.tinkerhelpwindow/9end.rwd +4 -0
  101. data/gui/tinkerbackwindows/superant.com.versionwindow/1appname.rwd +19 -0
  102. data/gui/tinkerbackwindows/superant.com.versionwindow/helpaboutwindow.rwd +17 -0
  103. data/gui/zzcoreguiend/yy9rwdend.rwd +4 -0
  104. data/init.rb +277 -0
  105. data/installed/mpdmusicdata2.inf +2 -0
  106. data/installed/rwdwmpd-0.06.inf +10 -0
  107. data/installed/temp.rb +1 -0
  108. data/lang/en/rwdcore/languagefile.rb +58 -0
  109. data/lang/es/rwdcore/languagefile-es.rb +62 -0
  110. data/lang/fr/rwdcore/languagefile.rb +64 -0
  111. data/lang/jp/rwdcore/languagefile.rb +72 -0
  112. data/lang/nl/rwdcore/languagefile.rb +75 -0
  113. data/lib/librmpd.rb +1152 -0
  114. data/lib/mpdserver.rb +1204 -0
  115. data/lib/rconftool.rb +387 -0
  116. data/lib/rwd/browser.rb +123 -0
  117. data/lib/rwd/ftools.rb +174 -0
  118. data/lib/rwd/mime.rb +328 -0
  119. data/lib/rwd/net.rb +876 -0
  120. data/lib/rwd/ruby.rb +889 -0
  121. data/lib/rwd/rwd.rb +1422 -0
  122. data/lib/rwd/sgml.rb +236 -0
  123. data/lib/rwd/thread.rb +63 -0
  124. data/lib/rwd/tree.rb +371 -0
  125. data/lib/rwd/xml.rb +101 -0
  126. data/lib/rwdthemes/default.rwd +317 -0
  127. data/lib/rwdthemes/pda.rwd +72 -0
  128. data/lib/rwdthemes/windowslike.rwd +171 -0
  129. data/lib/zip/ioextras.rb +114 -0
  130. data/lib/zip/stdrubyext.rb +111 -0
  131. data/lib/zip/tempfile_bugfixed.rb +195 -0
  132. data/lib/zip/zip.rb +1378 -0
  133. data/lib/zip/zipfilesystem.rb +558 -0
  134. data/lib/zip/ziprequire.rb +61 -0
  135. data/music/classicalmues.mp3 +0 -0
  136. data/rwd_files/HowTo_Mpd.txt +136 -0
  137. data/rwd_files/HowTo_Tinker.txt +482 -0
  138. data/rwd_files/HowTo_TinkerWin2.txt +202 -0
  139. data/rwd_files/Readme.txt +57 -0
  140. data/rwd_files/RubyWebDialogs.html +6 -0
  141. data/rwd_files/favicon.ico +0 -0
  142. data/rwd_files/rdoc-style.css +175 -0
  143. data/rwd_files/rwdapplications.html +54 -0
  144. data/rwd_files/tinker.png +0 -0
  145. data/rwdconfig.dist +22 -0
  146. data/rwdmpd.rb +1 -0
  147. data/tests/RubyGauge.rb +179 -0
  148. data/tests/checkdepends.sh +4 -0
  149. data/tests/cleancnf.sh +6 -0
  150. data/tests/makedist-rwdwmpd.rb +58 -0
  151. data/tests/makedist.rb +66 -0
  152. data/tests/rdep.rb +354 -0
  153. data/tests/totranslate.lang +93 -0
  154. data/zips/rwdwaddresses-1.06.zip +0 -0
  155. data/zips/rwdwcalc-0.62.zip +0 -0
  156. data/zips/rwdwfoldeditor-0.04.zip +0 -0
  157. data/zips/rwdwgutenberg-0.09.zip +0 -0
  158. data/zips/rwdwmpd-0.06.zip +0 -0
  159. data/zips/rwdwruby-1.07.zip +0 -0
  160. data/zips/temp.rb +1 -0
  161. data/zips/tinkerbellw-0.02.zip +0 -0
  162. data/zips/wrubyslippers-1.06.zip +0 -0
  163. metadata +220 -0
@@ -0,0 +1,2 @@
1
+ #rwdwmusic data
2
+ music/
@@ -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
@@ -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 => "せんた&#12367",
15
+ :documents => "オンラインマニュア&#12523",
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
+
@@ -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