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.
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