jsgui3-server 0.0.121 → 0.0.122

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 (278) hide show
  1. package/.vscode/settings.json +6 -0
  2. package/README.md +10 -10
  3. package/controls/Active_HTML_Document.js +116 -116
  4. package/controls/README.md +7 -7
  5. package/controls/page/admin.js +74 -74
  6. package/controls/panel/admin.js +11 -11
  7. package/examples/_css/basic.css +913 -913
  8. package/examples/_css/database-control.css +51 -51
  9. package/examples/_css/jsgui.css +66 -66
  10. package/examples/_css/multi-layout.css +23 -23
  11. package/examples/_css/style.css +1669 -1669
  12. package/examples/_css/top-and-bottom-bars.css +54 -54
  13. package/examples/box/1) square box/client.js +188 -188
  14. package/examples/box/1) square box/server.js +112 -112
  15. package/examples/box/2) twenty square boxes/css flex wrap/client.js +248 -248
  16. package/examples/box/2) twenty square boxes/css flex wrap/server.js +112 -112
  17. package/examples/boxes/square_boxes.js +45 -48
  18. package/examples/boxes/square_boxes_client.js +132 -136
  19. package/examples/client-side-popup-menu-button.html +93 -93
  20. package/examples/color_palette.js +51 -51
  21. package/examples/color_palette_client.js +95 -95
  22. package/examples/controls/1) window/client.js +186 -186
  23. package/examples/controls/1) window/server.js +117 -117
  24. package/examples/controls/10) window, mirrored text inputs/client.js +320 -320
  25. package/examples/controls/10) window, mirrored text inputs/server.js +117 -117
  26. package/examples/controls/11) window, mirrored text fields/client.js +493 -251
  27. package/examples/controls/11) window, mirrored text fields/server.js +117 -117
  28. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/client.js +613 -331
  29. package/examples/controls/11b) window, shared Data_Object model mirrored text fields/server.js +117 -117
  30. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/client.js +617 -617
  31. package/examples/controls/11c) window, shared Data_Value model mirrored text fields/server.js +117 -117
  32. package/examples/controls/11d) window, shared model mirrored integer text fields/client.js +611 -280
  33. package/examples/controls/11d) window, shared model mirrored integer text fields/server.js +134 -22
  34. package/examples/controls/12) window, Select_Options control/client.js +435 -452
  35. package/examples/controls/12) window, Select_Options control/server.js +117 -117
  36. package/examples/controls/2) two windows/client.js +193 -193
  37. package/examples/controls/2) two windows/server.js +113 -113
  38. package/examples/controls/3) five windows/client.js +217 -217
  39. package/examples/controls/3) five windows/server.js +116 -115
  40. package/examples/controls/4) window, tabbed panel/client.js +54 -225
  41. package/examples/controls/4) window, tabbed panel/server.js +17 -117
  42. package/examples/controls/5) window, grid/client.js +204 -484
  43. package/examples/controls/5) window, grid/server.js +117 -119
  44. package/examples/controls/6) window, color_palette/client.js +204 -204
  45. package/examples/controls/6) window, color_palette/server.js +117 -117
  46. package/examples/controls/7) window, month_view/client.js +40 -231
  47. package/examples/controls/7) window, month_view/server.js +117 -117
  48. package/examples/controls/8) window, checkbox/client.js +247 -209
  49. package/examples/controls/8) window, checkbox/server.js +117 -117
  50. package/examples/controls/9) window, date picker/client.js +303 -303
  51. package/examples/controls/9) window, date picker/server.js +117 -117
  52. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +398 -398
  53. package/examples/controls/9b) window, shared data.model mirrored date pickers/server.js +117 -117
  54. package/examples/controls/__old/_html-server-color-palette.js +114 -114
  55. package/examples/controls/__old/html-server-combo-box.js +104 -104
  56. package/examples/controls/__old/html-server-list.js +98 -98
  57. package/examples/controls/__old/html-server-popup-menu-button.js +114 -114
  58. package/examples/controls/__old/html-server-start-stop-toggle-button.js +146 -146
  59. package/examples/controls/__old/scs-arrow-button.js +36 -36
  60. package/examples/controls/__old/scs-date-picker.js +157 -157
  61. package/examples/controls/__old/scs-file-browser.js +82 -82
  62. package/examples/controls/__old/scs-item.js +159 -159
  63. package/examples/controls/__old/scs-month-arrow-selector.js +126 -126
  64. package/examples/controls/__old/scs-month-view.js +94 -94
  65. package/examples/controls/__old/scs-start-stop-toggle-button.js +40 -40
  66. package/examples/controls/__old/scs-tree.js +49 -49
  67. package/examples/controls/__old/scs-year-arrow-selector.js +127 -127
  68. package/examples/demos/date-picker.js +119 -119
  69. package/examples/demos/explain-encapsulation.js +9 -9
  70. package/examples/demos/resizing.js +35 -35
  71. package/examples/demos/server_time.js +6 -6
  72. package/examples/grids/grid_1.js +45 -45
  73. package/examples/grids/grid_1_client.js +329 -329
  74. package/examples/html-rendering.js +20 -20
  75. package/examples/html-server.js +105 -105
  76. package/examples/introducing jsgui3/server.js +110 -110
  77. package/examples/mx_display/mx_display_1.js +45 -45
  78. package/examples/mx_display/mx_display_1_client.js +444 -444
  79. package/fs2.js +1836 -1836
  80. package/http/responders/HTTP_Responder.js +15 -15
  81. package/http/responders/static/Static_Route_HTTP_Responder.js +105 -105
  82. package/module.js +34 -34
  83. package/old/_single-control-server.js +418 -418
  84. package/old/single-control-server.js +368 -368
  85. package/old/single-page-app.js +131 -131
  86. package/package.json +42 -42
  87. package/page-context.js +92 -92
  88. package/publishers/helpers/assigners/Assigner.js +10 -10
  89. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +150 -150
  90. package/publishers/helpers/assigners/static-headers/Single_Control_Webpage_Server_Static_Headers_Assigner.js +109 -109
  91. package/publishers/helpers/assigners/static-routes/Single_Control_Webpage_Server_Static_Routes_Assigner.js +91 -91
  92. package/publishers/helpers/assigners/static-uncompressed-response-buffers/Single_Control_Webpage_Server_Static_Uncompressed_Response_Buffers_Assigner.js +104 -104
  93. package/publishers/helpers/preparers/static/bundle/Ready_To_Serve_Preparer.js +18 -18
  94. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +44 -44
  95. package/publishers/http-function-publisher.js +212 -212
  96. package/publishers/http-html-page-publisher.js +5 -5
  97. package/publishers/http-html-publisher.js +24 -24
  98. package/publishers/http-js-publisher.js +135 -135
  99. package/publishers/http-observable-publisher.js +124 -124
  100. package/publishers/http-publisher.js +53 -53
  101. package/publishers/http-resource-publisher.js +325 -325
  102. package/publishers/http-webpage-publisher.js +659 -658
  103. package/publishers/http-webpageorsite-publisher.js +343 -343
  104. package/publishers/http-website-publisher.js +640 -640
  105. package/publishers/notes.md +9 -9
  106. package/resources/README.md +16 -16
  107. package/resources/_old_website-javascript-resource.js +994 -994
  108. package/resources/_old_website-resource.js +507 -507
  109. package/resources/compile/server-resource-compilation.js +43 -43
  110. package/resources/data-resource.js +118 -118
  111. package/resources/fs-resource.js +146 -146
  112. package/resources/jsbuilder/Abstract_Single_Declaration.js +105 -105
  113. package/resources/jsbuilder/Abstract_Single_Declaration_Sequence.js +42 -42
  114. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node.js +61 -61
  115. package/resources/jsbuilder/JS_AST/JS_AST_Abstract_Node_Group.js +41 -41
  116. package/resources/jsbuilder/JS_AST/JS_AST_Group_Shared.js +61 -61
  117. package/resources/jsbuilder/JS_AST/JS_AST_Node.js +93 -93
  118. package/resources/jsbuilder/JS_AST/JS_AST_Node_0-Core.js +253 -253
  119. package/resources/jsbuilder/JS_AST/JS_AST_Node_1-Babel.js +337 -337
  120. package/resources/jsbuilder/JS_AST/JS_AST_Node_10-Changing.js +39 -39
  121. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.1-Child.js +96 -96
  122. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.2-Parent.js +37 -37
  123. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.1.3-Ancestor.js +61 -61
  124. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.2-Inner.js +43 -43
  125. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.3-All.js +72 -72
  126. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.4-Sibling.js +92 -92
  127. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.5-Available_In_Scope.js +29 -29
  128. package/resources/jsbuilder/JS_AST/JS_AST_Node_2.9-Signature.js +116 -116
  129. package/resources/jsbuilder/JS_AST/JS_AST_Node_3-Basics.js +159 -159
  130. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.0-Basics_First.js +178 -178
  131. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.1-Basics_Second.js +87 -87
  132. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.0.99-Basics_Last.js +91 -91
  133. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1-Basics_Each.js +136 -136
  134. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.1.5-Basics_Count.js +73 -73
  135. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.2-Basics_Filter.js +39 -39
  136. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.3-Basics_Collect.js +85 -85
  137. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.4-Basics_Select.js +42 -42
  138. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.5-Basics_Find.js +40 -40
  139. package/resources/jsbuilder/JS_AST/JS_AST_Node_3.6-Basics_Callmap.js +54 -54
  140. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.0-Index_Indexes.js +45 -45
  141. package/resources/jsbuilder/JS_AST/JS_AST_Node_4.1-Index.js +343 -343
  142. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.0-Category.js +38 -38
  143. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.1-Category_Identifier.js +30 -30
  144. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.2-Category_Literal.js +28 -28
  145. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.3-Category_Expression.js +26 -26
  146. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.4-Category_Pattern.js +8 -8
  147. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.5-Category_Declaration.js +43 -43
  148. package/resources/jsbuilder/JS_AST/JS_AST_Node_5.6-Category_Statement.js +21 -21
  149. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.0-Type.js +89 -89
  150. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.1-Type_Class_Declaration.js +8 -8
  151. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.2-Type_Variable_Declaration.js +27 -27
  152. package/resources/jsbuilder/JS_AST/JS_AST_Node_6.3-Type_Variable_Declarator.js +28 -28
  153. package/resources/jsbuilder/JS_AST/JS_AST_Node_7-Query.js +736 -736
  154. package/resources/jsbuilder/JS_AST/JS_AST_Node_8-Features.js +64 -64
  155. package/resources/jsbuilder/JS_AST/JS_AST_Node_9-Planning.js +31 -31
  156. package/resources/jsbuilder/JS_AST/JS_AST_Node_Arrangement.js +15 -15
  157. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Declared_Object.js +305 -305
  158. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature.js +77 -77
  159. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declaration.js +248 -248
  160. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Node_Feature_Declarator.js +138 -138
  161. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature.js +10 -10
  162. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exported.js +100 -100
  163. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Feature_Exports.js +60 -60
  164. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/JS_AST_Root_Node_Interpreted.js +179 -179
  165. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/_JSGUI_Root_Node_Interpreted.js +43 -43
  166. package/resources/jsbuilder/JS_AST/JS_AST_Node_Feature/JS_AST_Root_Node_Feature/special_case_objectassign_to_object.js +12 -12
  167. package/resources/jsbuilder/JS_AST/JS_AST_Node_Group.js +35 -35
  168. package/resources/jsbuilder/JS_AST/JS_AST_Operation.js +11 -11
  169. package/resources/jsbuilder/JS_AST/JS_AST_Operation_On_Relationship.js +31 -31
  170. package/resources/jsbuilder/JS_AST/JS_AST_Ordered_Relationship_Node_To_Group.js +37 -37
  171. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal.js +39 -39
  172. package/resources/jsbuilder/JS_AST/JS_AST_Ordinal_Relationship.js +25 -25
  173. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_To_Group.js +200 -200
  174. package/resources/jsbuilder/JS_AST/JS_AST_Relationship_Node_Within_Group_To_Node.js +43 -43
  175. package/resources/jsbuilder/JS_AST/_JS_AST_Node_3.8-Query_Features.js +76 -76
  176. package/resources/jsbuilder/JS_AST/query/enable_array_as_queryable.js +227 -227
  177. package/resources/jsbuilder/JS_AST/query/find_object_keys.js +404 -404
  178. package/resources/jsbuilder/JS_AST/query/node_queries.js +8 -8
  179. package/resources/jsbuilder/JS_AST/query/root_query_identidy.js +11 -11
  180. package/resources/jsbuilder/JS_AST_Node_Extended/JSGUI_Singular_Declaration.js +85 -85
  181. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Declaration.js +123 -123
  182. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended.js +87 -87
  183. package/resources/jsbuilder/JS_AST_Node_Extended/JS_AST_Node_Extended_0-Core.js +10 -10
  184. package/resources/jsbuilder/JS_Builder.js +10 -10
  185. package/resources/jsbuilder/JS_File/Feature/JS_File_Declared_Object.js +31 -31
  186. package/resources/jsbuilder/JS_File/Feature/JS_File_Exported_Object_Info.js +25 -25
  187. package/resources/jsbuilder/JS_File/Feature/JS_File_Exports.js +78 -78
  188. package/resources/jsbuilder/JS_File/Feature/JS_File_Feature.js +17 -17
  189. package/resources/jsbuilder/JS_File/Feature/JS_File_Imported_Object_Info.js +25 -25
  190. package/resources/jsbuilder/JS_File/Feature/JS_File_Imports.js +8 -8
  191. package/resources/jsbuilder/JS_File/JS_File.js +12 -12
  192. package/resources/jsbuilder/JS_File/JS_File_0-Core.js +202 -202
  193. package/resources/jsbuilder/JS_File/JS_File_1-Early_Parse.js +175 -175
  194. package/resources/jsbuilder/JS_File/JS_File_2-Babel.js +81 -81
  195. package/resources/jsbuilder/JS_File/JS_File_3-JS_AST_Node.js +86 -86
  196. package/resources/jsbuilder/JS_File/JS_File_4-Query.js +413 -413
  197. package/resources/jsbuilder/JS_File/JS_File_4.1-Query_Features.js +414 -414
  198. package/resources/jsbuilder/JS_File/JS_File_5-Planning.js +59 -59
  199. package/resources/jsbuilder/JS_File/JS_File_6-Changing.js +24 -24
  200. package/resources/jsbuilder/JS_File/JS_File_Export_Reference.js +12 -12
  201. package/resources/jsbuilder/JS_File/JS_File_Import_Reference.js +23 -23
  202. package/resources/jsbuilder/JS_File/JS_File_Import_References.js +31 -31
  203. package/resources/jsbuilder/JS_File/JS_File_Processor.js +16 -16
  204. package/resources/jsbuilder/JS_File/JS_Files.js +15 -15
  205. package/resources/jsbuilder/Module.js +14 -14
  206. package/resources/jsbuilder/Platform.js +13 -13
  207. package/resources/jsbuilder/Platforms.js +69 -69
  208. package/resources/jsbuilder/Project.js +109 -109
  209. package/resources/jsbuilder/Reference.js +1 -1
  210. package/resources/jsbuilder/Reference_Sequence.js +16 -16
  211. package/resources/jsbuilder/Scope.js +29 -29
  212. package/resources/jsbuilder/Variable_Name_Provider.js +42 -42
  213. package/resources/jsbuilder/_JS_File.js +225 -225
  214. package/resources/jsbuilder/ast_query.js +20 -20
  215. package/resources/jsbuilder/babel/babel_consts.js +162 -162
  216. package/resources/jsbuilder/babel/babel_node_tools.js +541 -541
  217. package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +923 -904
  218. package/resources/jsbuilder/build.js +16 -16
  219. package/resources/jsbuilder/platform_notes.md +66 -66
  220. package/resources/jsbuilder/test/test_ast_node.js +381 -381
  221. package/resources/jsbuilder/test/test_js_file.js +303 -303
  222. package/resources/jsbuilder/test/test_project.js +157 -157
  223. package/resources/local-server-info-resource.js +96 -96
  224. package/resources/notes.txt +10 -10
  225. package/resources/old/website-image-resource.js +1185 -1185
  226. package/resources/process-js.js +498 -498
  227. package/resources/processors/bundlers/bundle.js +29 -29
  228. package/resources/processors/bundlers/bundler.js +23 -23
  229. package/resources/processors/bundlers/css-bundler.js +234 -234
  230. package/resources/processors/bundlers/js/JS_Bundler.js +51 -51
  231. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +388 -391
  232. package/resources/processors/bundlers/js/esbuild/Bundler_Using_ESBuild.js +8 -8
  233. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +188 -188
  234. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +191 -192
  235. package/resources/processors/bundlers/js/esbuild/_Old_CSS_Extractor.js +239 -239
  236. package/resources/processors/bundlers/js-bundler.js +263 -263
  237. package/resources/processors/bundlers/test_ast.js +73 -73
  238. package/resources/processors/bundlers/webpage-bundler.js +404 -404
  239. package/resources/processors/bundlers/website-bundler.js +22 -22
  240. package/resources/processors/extractors/Extractor.js +9 -11
  241. package/resources/processors/extractors/js/css_and_js/AST_Node/CSS_And_JS_From_JS_String_Using_AST_Node_Extractor.js +239 -254
  242. package/resources/processors/extractors/js/css_and_js/CSS_And_JS_From_JS_String_Extractor.js +3 -3
  243. package/resources/processors/extractors/string/Pos_Span_String_Extractor.js +93 -93
  244. package/resources/server-installed-tools.js +28 -28
  245. package/resources/server-resource-pool.js +41 -41
  246. package/resources/website-audio-resource.js +735 -735
  247. package/resources/website-css-resource.js +411 -411
  248. package/resources/website-image-resource.js +412 -412
  249. package/resources/website-javascript-resource-processor.js +908 -908
  250. package/resources/website-javascript-resource.js +874 -874
  251. package/resources/website-resource-processor.js +10 -10
  252. package/resources/website-resource.js +164 -164
  253. package/resources/website-static-html-resource.js +199 -199
  254. package/resources/website-template-html-resource.js +231 -231
  255. package/roadmap.md +75 -75
  256. package/server.js +609 -573
  257. package/static-page-context.js +13 -13
  258. package/website/webpage.js +81 -81
  259. package/website/website-group.js +15 -15
  260. package/website/website.js +260 -260
  261. package/examples/controls/11d) window, shared model mirrored integer text fields/both.js +0 -17
  262. package/examples/controls/13) window, shared model mirrored lat_long/client.js +0 -933
  263. package/examples/controls/13) window, shared model mirrored lat_long/server.js +0 -50
  264. package/examples/controls/14) window, control compositional model/client.js +0 -328
  265. package/examples/controls/14) window, control compositional model/server.js +0 -118
  266. package/examples/controls/14a) window, control spec has compositional model/client.js +0 -440
  267. package/examples/controls/14a) window, control spec has compositional model/server.js +0 -118
  268. package/examples/controls/15) window, text field/client.js +0 -256
  269. package/examples/controls/15) window, text field/server.js +0 -39
  270. package/examples/controls/16) Window([Text_Input])/client.js +0 -266
  271. package/examples/controls/16) Window([Text_Input])/server.js +0 -109
  272. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/client.js +0 -494
  273. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/isomorphic.js +0 -24
  274. package/examples/controls/16a) Window([Text_Input]) Integer data.model.data_type/server.js +0 -73
  275. package/examples/controls/2b) two window, context menus/client.js +0 -193
  276. package/examples/controls/2b) two window, context menus/server.js +0 -114
  277. package/examples/controls/4a) window, tabbed panel with various controls inside/client.js +0 -233
  278. package/examples/controls/4a) window, tabbed panel with various controls inside/server.js +0 -118
@@ -1,735 +1,735 @@
1
-
2
- // Need to maintain the various concepts applying here.
3
- // Get them working or throwing errors / set to NYI if they are not so simple to fix / implement.
4
-
5
- /*
6
- if (typeof define !== 'function') {
7
- var define = require('amdefine')(module);
8
- }
9
-
10
- // I would like my own (fast) way of reading MP3 metadata.
11
-
12
- // Had a problem seeking later parts of the track in Chrome. It would request a few seconds too little audio from the server.
13
- // Seems like Chrome estimated positions for VBR audio are out.
14
- // This bay be improved by changing to a constant bitrate (though that is less efficient encoding, generally)
15
-
16
- // Other parts of the system are likely to be more important.
17
- // It may be useful to have an interface to administer the site's audio.
18
-
19
- // Browse tracks, and encode them into different bit rates and formats.
20
- // Maintain copies of the tracks in different bit rates and formats.
21
-
22
-
23
- define(['module', 'path', 'fs', 'url', '../../web/jsgui-html', 'os', 'http', 'url', './resource',
24
- '../../web/jsgui-je-suis-xml', 'cookies', '../../fs/jsgui-node-fs2-core', '../../audio/jsgui-node-audio-metadata', 'crypto'],
25
-
26
- function(module, path, fs, url, jsgui, os, http, libUrl,
27
- Resource, JeSuisXML, Cookies, fs2, audio_metadata, crypto) {
28
- */
29
-
30
- const path = require('path'), fs = require('fs'), url = require('url'), jsgui = require('../../web/jsgui-html'), os = require('os'), http = require('http'), libUrl = require('url'),
31
- Resource = require('./resource'), Cookies = require('./cookies'), fs2 = require('../../fs/jsgui-node-fs2-core'), audio_metadata = require('../../audio/jsgui-node-audio-metadata'), crypto = require('crypto');
32
-
33
-
34
- var stringify = jsgui.stringify, each = jsgui.eac, arrayify = jsgui.arrayify, tof = jsgui.tof;
35
- var filter_map_by_regex = jsgui.filter_map_by_regex;
36
- var Class = jsgui.Class, Data_Object = jsgui.Data_Object, Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
37
- var fp = jsgui.fp, is_defined = jsgui.is_defined;
38
- var Collection = jsgui.Collection;
39
-
40
- // This resource may have quite a lot of functionality put in to deal with
41
- // seriving images in an optimized way.
42
- // Want this so it also serves the developer in that images can be put in place
43
- // and modified easily in an unoptimized way. Then they get put in place in an
44
- // optimized way on request or automatically. Want to incorporate sprite sheet generation
45
- // here. This should handle requests for individual images, but it's also possible sprites
46
- // could be requested. If that's the case, maybe it should pass it onto a sprite resource.
47
- // It would be really good to have practically instant sprite generation, using C / C++
48
- // and maybe OpenCL.
49
- // It could be requests to a sprite resource that returns a predefined selection of
50
- // assets.
51
- // The image resource may also be called upon to return rescaled versions.
52
- // That's something that OpenCL would also be very fast at.
53
- // The image / spritesheet resources may be connected to other database resources that provide
54
- // caching and indexing of images.
55
- // These would most likely be abstractions over data resources.
56
-
57
- // Want to make an image interface to a flexible db interface.
58
- // Serving and caching optimized images would be cool.
59
-
60
- // Rather than relying on storing image versions in a DB (which would be cool, esp for distributed)
61
- // we can store image versions + spritesheets on the local disk.
62
- // Cache them in RAM as well.
63
- // Storing them in GPU RAM would be very cool, especially if from there we can get versions with
64
- // different operations done, or the output of operations.
65
-
66
-
67
- // May need to change around a fair few references to make it workable.
68
- // May need some more complicated logic to change it to the path for service.
69
-
70
-
71
- // need to see what type of image it is.
72
- var mime_types = {
73
- 'acc': 'audio/acc',
74
- 'mp4': 'audio/mp4',
75
- 'mp3': 'audio/mpeg3',
76
- 'mpeg': 'audio/mpeg',
77
- 'ogg': 'audio/ogg',
78
- 'wav': 'audio/wav',
79
- 'webm': 'audio/webm'
80
- };
81
-
82
- var serve_audio_file_from_disk = fp(function(a, sig) {
83
-
84
- var filePath, start_pos = 0, end_pos, response;
85
- var using_byte_range = false;
86
-
87
- if (a.l == 2) {
88
- filePath = a[0];
89
- response = a[1];
90
-
91
- }
92
- if (a.l == 3) {
93
- filePath = a[0];
94
- start_pos = a[1];
95
- response = a[2];
96
- using_byte_range = true;
97
-
98
- }
99
- if (a.l == 4) {
100
- filePath = a[0];
101
- start_pos = a[1];
102
- end_pos = a[2]
103
- response = a[3];
104
- using_byte_range = true;
105
- }
106
- console.log('serve_audio_file_from_disk filePath ', filePath);
107
-
108
- var extname = path.extname(filePath);
109
- console.log('extname ' + extname);
110
-
111
- var extension = extname.substr(1);
112
- console.log('extension ' + extension);
113
-
114
-
115
- // then return the right MIME type for that extension.
116
-
117
- // No, don't load the image file as a string.
118
-
119
- // fs loadfile
120
- // async, then serve it with the correct mime type, write to the response buffer.
121
-
122
- // can this be streamed to the response buffer?
123
-
124
- //console.log('filePath', filePath);
125
-
126
- // This was served from Express in another app:
127
- /*
128
- Accept-Ranges:bytes
129
- Cache-Control:public, max-age=0
130
- Connection:keep-alive
131
- Content-Length:7831024
132
- Content-Range:bytes 0-7831023/7831024
133
- Content-Type:audio/mpeg
134
- Date:Fri, 02 May 2014 15:41:56 GMT
135
- ETag:"7831024-1357308361000"
136
- Last-Modified:Fri, 04 Jan 2013 14:06:01 GMT
137
- X-Powered-By:Express
138
-
139
- Currently served:
140
-
141
- Accept-Ranges:bytes
142
- Connection:keep-alive
143
- Content-Length:7831024
144
- Content-Range:bytes 0-7831024/7831024
145
- Content-Type:audio/mpeg3
146
- Date:Fri, 02 May 2014 18:01:47 GMT
147
-
148
-
149
- */
150
-
151
- // It seems like this needs to present an etag to the client in order to work successfully.
152
-
153
-
154
-
155
-
156
- // May be better to use fs.read
157
- // Serve this as a stream
158
- // The client may not request it so quickly.
159
- // However, may not want lots of access to the disk, so storing it in RAM while being served may make sense.
160
-
161
-
162
-
163
-
164
- //
165
-
166
- /*
167
-
168
- fs.open('./data/index.html', 'r', function(err, fd) {
169
- if(err) throw err;
170
- var str = new Buffer(3);
171
- fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead, buffer) {
172
- if(err) throw err;
173
- console.log(err, bytesRead, buffer);
174
- fs.close(fd, ChaipaKwa, are you there?
175
- function() {
176
- console.log('Done');
177
- });
178
- });
179
- });
180
-
181
- */
182
-
183
- // This current code is probably more memory efficient.
184
- // A greater efficiency could be gained (possibly) by storing the whole MP3 in memory while it is being served,
185
- // and using the same buffer to send to more than 1 client.
186
-
187
- fs.stat(filePath, function (err, stats) {
188
- if (err) {
189
-
190
- // The file probably was not found.
191
- // Return a 404.
192
-
193
- //response.status(404).send('Not found');
194
-
195
- response.writeHead(404, {
196
-
197
- "Content-Type": "text/plain"
198
-
199
- });
200
-
201
- response.write("404 Not Found\n");
202
-
203
- response.end();
204
-
205
-
206
- //throw err;
207
- } else {
208
- console.log('stats.size', stats.size);
209
-
210
- //var l = stats.size;
211
-
212
- var l;
213
-
214
- var response_code = 200;
215
- //if (start_pos > 0) {
216
- // response_code = 206;
217
- //}
218
-
219
-
220
- if (using_byte_range) {
221
- response_code = 206;
222
- if (start_pos) {
223
- l = stats.size - start_pos ;
224
-
225
- }
226
-
227
-
228
-
229
- var rs_opts = {
230
- 'start': start_pos
231
- };
232
-
233
- if (end_pos) {
234
- rs_opts.end = end_pos + 1;
235
- l = end_pos;
236
- }
237
-
238
- if (start_pos && end_pos) {
239
- l = (end_pos + 1) - start_pos;
240
- }
241
-
242
-
243
- } else {
244
- l = stats.size;
245
- }
246
-
247
-
248
- console.log('rs_opts', rs_opts);
249
- var rs = fs.createReadStream(filePath, rs_opts);
250
-
251
- rs.pause();
252
-
253
- var c = 0;
254
-
255
- // Response code 206 for partial content.
256
- // Need to only do this if the browser is asking for partial content though.
257
-
258
- // It seems like partial requests rely on etags.
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
- // Needs to have a new etag for each file.
268
- // Can use a hash of the file path.
269
-
270
-
271
- var key = 'ready salted';
272
- var hash = crypto.createHmac('sha1', key).update(filePath).digest('hex');
273
-
274
- // Get last modified time from file.
275
-
276
-
277
- // Need to handle 0-n ranges
278
- // iOS starts the audio download with a 0-1 range.
279
-
280
- // Seems that with the range request we should return 1 more byte.
281
-
282
-
283
-
284
- // Don't necessarily do content-range.
285
-
286
- var o_head = {'Content-Type': mime_types[extension],
287
- //'Accept-Ranges': 'bytes',
288
-
289
- 'ETag': hash,
290
- //'Last-Modified': 'Fri, 04 Jan 2013 14:06:01 GMT',
291
- 'Last-Modified': stats.mtime,
292
-
293
- 'Content-Length': l//,
294
-
295
- // Not serving the whole content (fill amount - 1) gets the 206 response to work.
296
- //'Content-Range': 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
297
- };
298
-
299
- if (using_byte_range) {
300
- o_head['Accept-Ranges'] = 'bytes';
301
- start_pos = start_pos || 0;
302
-
303
- if (end_pos) {
304
- o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (end_pos) + '/' + stats.size
305
- } else {
306
- o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
307
- }
308
-
309
-
310
- }
311
-
312
- console.log('o_head', o_head);
313
-
314
-
315
- response.writeHead(response_code, o_head);
316
-
317
- //response.pipe()
318
-
319
- rs.pipe(response);
320
-
321
-
322
-
323
- //rs.on('data', function(chunk) {
324
- //c = c + chunk.length;
325
- //console.log('got %d bytes of data', chunk.length);
326
- //console.log('bytes read so far', c);
327
- //});
328
- rs.resume();
329
-
330
-
331
-
332
-
333
-
334
-
335
- /*
336
- fs.open(filePath, 'r', function(err, fd) {
337
- if (err) {
338
- throw err;
339
- } else {
340
- // Do we know how long the file is?
341
- // We need to get the metadata first?
342
-
343
- // Want to stream the file, sequentially.
344
-
345
-
346
-
347
-
348
- }
349
- })
350
- */
351
-
352
- }
353
-
354
- });
355
-
356
-
357
-
358
- /*
359
-
360
- fs.readFile(filePath, function(err, data) {
361
- if (err) {
362
- throw err;
363
- } else {
364
- console.log('cb readfile');
365
- response.writeHead(200, {'Content-Type': mime_types[extension],
366
- 'Accept-Ranges': 'bytes',
367
- 'Content-Length': data.length,
368
- 'Content-Range': 'bytes 0-' + data.length + '/' + data.length
369
- });
370
-
371
- // Accept-Ranges:bytes
372
- response.end(data, 'binary');
373
-
374
- }
375
- });
376
- */
377
-
378
-
379
- //fs2.load_file_as_string(filePath, function (err, data) {
380
- // if (err) {
381
- // throw err;
382
- // } else {
383
- // //var servableJs = updateReferencesForServing(data);
384
- // response.writeHead(200, {'Content-Type': mime_types[extension]});
385
- // response.end(data);
386
- // }
387
- //});
388
- });
389
-
390
-
391
- var Site_Audio = Resource.extend({
392
-
393
-
394
- 'init': function(spec) {
395
- super(spec);
396
- //this._super(spec);
397
-
398
- this.meta.set('custom_paths', new Data_Object({}));
399
- // Those are custom file paths.
400
-
401
- // could have a collection of directories, indexed by name, that get served.
402
-
403
- // Index the collection by string value?
404
- this.meta.set('served_directories', new Collection({'index_by': 'name'}));
405
- },
406
- 'start': function(callback) {
407
- // Load the tracks and find out their lengths.
408
-
409
- console.log('Site Audio Resource Start');
410
-
411
- var meta = this.meta;
412
- var albums = meta.get('albums');
413
-
414
- if (albums) {
415
- each(albums, function(album) {
416
- // We load the track length.
417
-
418
- var tracks = album.tracks;
419
-
420
- var l = tracks.length;
421
-
422
- each(tracks, function(track, i_track) {
423
- var track_base_name = (i_track + 1).toString();
424
- if (track_base_name.length == 1) {
425
- track_base_name = '0' + track_base_name;
426
- }
427
- var track_mp3_path = album.path + '/mp3/' + track_base_name + '.mp3';
428
- //console.log('track_mp3_path', track_mp3_path);
429
- // perhaps using call_multi
430
- // load this up, get the track length
431
- audio_metadata.from_file(track_mp3_path, function(err, metadata) {
432
- if (err) {
433
- throw err;
434
- } else {
435
- //console.log('metadata', metadata);
436
-
437
- var ms_duration = metadata.ms_duration;
438
- track.ms_duration = ms_duration;
439
-
440
- l--;
441
-
442
- if (l == 0) {
443
- //console.log('tracks', tracks);
444
- callback(null, true);
445
- }
446
-
447
- }
448
- })
449
-
450
-
451
- });
452
-
453
-
454
- });
455
-
456
- } else {
457
- callback(null, true);
458
- }
459
-
460
- //console.log('albums', albums);
461
- //console.log('tof(albums)', tof(albums));
462
-
463
-
464
-
465
- },
466
- 'serve_directory': function(path) {
467
- // Serves that directory, as any files given in that directory can be served from /js
468
- var served_directories = this.meta.get('served_directories');
469
- //console.log('served_directories ' + stringify(served_directories));
470
- //served_directories.push(path);
471
- served_directories.push({
472
- 'name': path
473
- });
474
- //console.log('served_directories ' + stringify(served_directories));
475
- //console.log('path ' + path);
476
-
477
-
478
- //throw 'stop';
479
-
480
-
481
-
482
- },
483
-
484
- // basically get requests, but can handle more than just get.
485
- 'process': function(req, res) {
486
- console.log('Site_JavaScript processing');
487
- var remoteAddress = req.connection.remoteAddress;
488
-
489
- var custom_paths = this.meta.get('custom_paths');
490
-
491
- var rurl = req.url;
492
-
493
- var pool = this.meta.get('pool');
494
- // should have a bunch of resources from the pool.
495
-
496
- //var pool_resources = pool.resources();
497
- //console.log('pool_resources ' + stringify(pool_resources));
498
-
499
- //console.log('req', req);
500
-
501
- var headers = req.headers;
502
- console.log('headers', headers);
503
-
504
- // bytes=6723861-
505
-
506
- var range = headers.range;
507
- console.log('range', range);
508
-
509
-
510
-
511
- var byte_start_pos;
512
- var byte_end_pos;
513
-
514
- if (range) {
515
- var s_range = range.split('=');
516
-
517
- console.log('s_range', s_range);
518
-
519
- var s_range_2 = s_range[1].split('-');
520
-
521
- console.log('s_range_2', s_range_2);
522
-
523
- if (s_range_2[0]) {
524
- byte_start_pos = parseInt(s_range_2[0], 10);
525
- }
526
- if (s_range_2[1]) {
527
- console.log('s_range_2[1]', s_range_2[1]);
528
- byte_end_pos = parseInt(s_range_2[1], 10);
529
- }
530
- }
531
-
532
- console.log('byte_start_pos', byte_start_pos);
533
- console.log('byte_end_pos', byte_end_pos);
534
-
535
- //if (range.substr())
536
-
537
-
538
-
539
-
540
-
541
- // It looks like this will need to handle byte ranges too.
542
-
543
-
544
-
545
-
546
- var wildcard_value = req.params.wildcard_value;
547
- //console.log('wildcard_value', wildcard_value);
548
-
549
- if (wildcard_value) {
550
- var s_path = wildcard_value.split('/');
551
- //console.log('s_path', s_path);
552
-
553
- if (s_path.length == 3) {
554
- var album_url_name = s_path[1];
555
- var track_url_name = s_path[2];
556
-
557
- var s_track_url_name = track_url_name.split('.');
558
- var track_base_name = s_track_url_name[0];
559
- var track_extension = s_track_url_name[1];
560
-
561
- //console.log('track_base_name', track_base_name);
562
- console.log('track_extension', track_extension);
563
-
564
- // Need to match it up with the resource's albums
565
-
566
-
567
-
568
- // Then load up and serve the file.
569
-
570
- //var media_file_path =
571
-
572
- // Likely to have been given specialised path info, in the metadata.
573
- // Could have been provided with an album's path.
574
-
575
- var meta = this.meta;
576
- //console.log('meta', meta);
577
-
578
- var albums = meta.get('albums');
579
- //console.log('albums', albums);
580
-
581
- var parsed_album_url_name = parseInt(album_url_name, 10);
582
- var i_album = parsed_album_url_name - 1;
583
-
584
- var album = albums[i_album];
585
-
586
-
587
- //var tracks = album.get('tracks');
588
- var tracks = album.tracks;
589
-
590
- var i_track = parseInt(track_base_name, 10);
591
-
592
- var s_track = i_track.toString();
593
- if (s_track.length == 1) {
594
- s_track = '0' + s_track;
595
- }
596
-
597
- //console.log('s_track', s_track);
598
-
599
- // Anyway, choose the right file (from mp3 dir for the moment)
600
-
601
- // Must also be able to serve ogg paths.
602
-
603
-
604
-
605
- var media_file_path = album.path + '/' + track_extension + '/' + s_track + '.' + track_extension;
606
- console.log('media_file_path', media_file_path);
607
- //console.log('res (response)', res);
608
-
609
- // Also, we may not want to serve the whole audio file, but to begin the stream.
610
- // Maybe we could keep the whole audio file in memory as a buffer.
611
- // Don't want lots of large temporary buffers.
612
-
613
-
614
-
615
-
616
- // Also need to take into account the byte range.
617
- // The serve audio function could be changed so that it can serve a byterange, eg x-
618
- // from x to the end
619
-
620
- if (byte_end_pos) {
621
- serve_audio_file_from_disk(media_file_path, byte_start_pos, byte_end_pos, res);
622
- } else {
623
-
624
- if (typeof byte_start_pos != 'undefined') {
625
- serve_audio_file_from_disk(media_file_path, byte_start_pos, res);
626
- } else {
627
- serve_audio_file_from_disk(media_file_path, res);
628
- }
629
-
630
-
631
- }
632
-
633
-
634
-
635
-
636
-
637
- //console.log('tracks', tracks);
638
-
639
- //
640
- }
641
- }
642
-
643
- //throw 'stop';
644
-
645
- /*
646
-
647
-
648
-
649
-
650
- var url_parts = url.parse(req.url, true);
651
- //console.log('url_parts ' + stringify(url_parts));
652
- var splitPath = url_parts.path.substr(1).split('/');
653
-
654
- // Want the path inside the resource as well.
655
-
656
- //console.log('resource site css splitPath ' + stringify(splitPath));
657
-
658
-
659
- if (rurl.substr(0, 1) == '/') rurl = rurl.substr(1);
660
- rurl = rurl.replace(/\./g, '☺');
661
- //console.log('rurl ' + rurl);
662
-
663
- var custom_response_entry = custom_paths.get(rurl);
664
- //console.log('custom_response_entry ' + stringify(custom_response_entry));
665
-
666
- // Should probably already be given the audio path, as well as the path within the audio path.
667
-
668
- // Custom audio resource publishers could seem like a decent business.
669
-
670
- if (custom_response_entry) {
671
- var tcr = tof(custom_response_entry);
672
- //console.log('tcr ' + tcr);
673
-
674
- if (tcr == 'data_value') {
675
- val = custom_response_entry.value();
676
- //console.log('val ' + val);
677
-
678
- var tval = tof(val);
679
-
680
- if (tval == 'string') {
681
- // then it should be a local file path, serve it.
682
- serve_image_file_from_disk(val, res);
683
- }
684
- }
685
- } else {
686
- //console.log('splitPath', splitPath);
687
- if (splitPath.length > 0) {
688
-
689
- if (splitPath[0] == 'audio') {
690
-
691
- if (splitPath.length > 1) {
692
- if (splitPath.length == 2) {
693
- var fileName = splitPath[1];
694
- //console.log('url_parts.path ' + url_parts.path);
695
- var filePath = url_parts.path.substr(1);
696
- //console.log('module.uri ' + module.uri);
697
- var val2 = path.dirname(module.uri);
698
- console.log('val2 ' + val2);
699
-
700
- var diskPath = '../../ws/audio/' + fileName;
701
-
702
- serve_image_file_from_disk(diskPath, res);
703
-
704
- } else {
705
- if (splitPath.length > 2) {
706
-
707
- // need to put the rest of it together...
708
-
709
- var fileName = splitPath.slice(1, splitPath.length).join('/');
710
- console.log('fileName', fileName);
711
-
712
-
713
- var filePath = url_parts.path.substr(1);
714
- //console.log('module.uri ' + module.uri);
715
- var val2 = path.dirname(module.uri);
716
- console.log('val2 ' + val2);
717
- var diskPath = '../../ws/audio/' + fileName;
718
-
719
- serve_image_file_from_disk(diskPath, res);
720
-
721
- }
722
-
723
- }
724
- }
725
- }
726
- }
727
- }
728
- */
729
- }
730
- });
731
-
732
- //return Site_Audio;
733
- //});
734
-
735
- module.exports = Site_Audio;
1
+
2
+ // Need to maintain the various concepts applying here.
3
+ // Get them working or throwing errors / set to NYI if they are not so simple to fix / implement.
4
+
5
+ /*
6
+ if (typeof define !== 'function') {
7
+ var define = require('amdefine')(module);
8
+ }
9
+
10
+ // I would like my own (fast) way of reading MP3 metadata.
11
+
12
+ // Had a problem seeking later parts of the track in Chrome. It would request a few seconds too little audio from the server.
13
+ // Seems like Chrome estimated positions for VBR audio are out.
14
+ // This bay be improved by changing to a constant bitrate (though that is less efficient encoding, generally)
15
+
16
+ // Other parts of the system are likely to be more important.
17
+ // It may be useful to have an interface to administer the site's audio.
18
+
19
+ // Browse tracks, and encode them into different bit rates and formats.
20
+ // Maintain copies of the tracks in different bit rates and formats.
21
+
22
+
23
+ define(['module', 'path', 'fs', 'url', '../../web/jsgui-html', 'os', 'http', 'url', './resource',
24
+ '../../web/jsgui-je-suis-xml', 'cookies', '../../fs/jsgui-node-fs2-core', '../../audio/jsgui-node-audio-metadata', 'crypto'],
25
+
26
+ function(module, path, fs, url, jsgui, os, http, libUrl,
27
+ Resource, JeSuisXML, Cookies, fs2, audio_metadata, crypto) {
28
+ */
29
+
30
+ const path = require('path'), fs = require('fs'), url = require('url'), jsgui = require('../../web/jsgui-html'), os = require('os'), http = require('http'), libUrl = require('url'),
31
+ Resource = require('./resource'), Cookies = require('./cookies'), fs2 = require('../../fs/jsgui-node-fs2-core'), audio_metadata = require('../../audio/jsgui-node-audio-metadata'), crypto = require('crypto');
32
+
33
+
34
+ var stringify = jsgui.stringify, each = jsgui.eac, arrayify = jsgui.arrayify, tof = jsgui.tof;
35
+ var filter_map_by_regex = jsgui.filter_map_by_regex;
36
+ var Class = jsgui.Class, Data_Object = jsgui.Data_Object, Enhanced_Data_Object = jsgui.Enhanced_Data_Object;
37
+ var fp = jsgui.fp, is_defined = jsgui.is_defined;
38
+ var Collection = jsgui.Collection;
39
+
40
+ // This resource may have quite a lot of functionality put in to deal with
41
+ // seriving images in an optimized way.
42
+ // Want this so it also serves the developer in that images can be put in place
43
+ // and modified easily in an unoptimized way. Then they get put in place in an
44
+ // optimized way on request or automatically. Want to incorporate sprite sheet generation
45
+ // here. This should handle requests for individual images, but it's also possible sprites
46
+ // could be requested. If that's the case, maybe it should pass it onto a sprite resource.
47
+ // It would be really good to have practically instant sprite generation, using C / C++
48
+ // and maybe OpenCL.
49
+ // It could be requests to a sprite resource that returns a predefined selection of
50
+ // assets.
51
+ // The image resource may also be called upon to return rescaled versions.
52
+ // That's something that OpenCL would also be very fast at.
53
+ // The image / spritesheet resources may be connected to other database resources that provide
54
+ // caching and indexing of images.
55
+ // These would most likely be abstractions over data resources.
56
+
57
+ // Want to make an image interface to a flexible db interface.
58
+ // Serving and caching optimized images would be cool.
59
+
60
+ // Rather than relying on storing image versions in a DB (which would be cool, esp for distributed)
61
+ // we can store image versions + spritesheets on the local disk.
62
+ // Cache them in RAM as well.
63
+ // Storing them in GPU RAM would be very cool, especially if from there we can get versions with
64
+ // different operations done, or the output of operations.
65
+
66
+
67
+ // May need to change around a fair few references to make it workable.
68
+ // May need some more complicated logic to change it to the path for service.
69
+
70
+
71
+ // need to see what type of image it is.
72
+ var mime_types = {
73
+ 'acc': 'audio/acc',
74
+ 'mp4': 'audio/mp4',
75
+ 'mp3': 'audio/mpeg3',
76
+ 'mpeg': 'audio/mpeg',
77
+ 'ogg': 'audio/ogg',
78
+ 'wav': 'audio/wav',
79
+ 'webm': 'audio/webm'
80
+ };
81
+
82
+ var serve_audio_file_from_disk = fp(function(a, sig) {
83
+
84
+ var filePath, start_pos = 0, end_pos, response;
85
+ var using_byte_range = false;
86
+
87
+ if (a.l == 2) {
88
+ filePath = a[0];
89
+ response = a[1];
90
+
91
+ }
92
+ if (a.l == 3) {
93
+ filePath = a[0];
94
+ start_pos = a[1];
95
+ response = a[2];
96
+ using_byte_range = true;
97
+
98
+ }
99
+ if (a.l == 4) {
100
+ filePath = a[0];
101
+ start_pos = a[1];
102
+ end_pos = a[2]
103
+ response = a[3];
104
+ using_byte_range = true;
105
+ }
106
+ console.log('serve_audio_file_from_disk filePath ', filePath);
107
+
108
+ var extname = path.extname(filePath);
109
+ console.log('extname ' + extname);
110
+
111
+ var extension = extname.substr(1);
112
+ console.log('extension ' + extension);
113
+
114
+
115
+ // then return the right MIME type for that extension.
116
+
117
+ // No, don't load the image file as a string.
118
+
119
+ // fs loadfile
120
+ // async, then serve it with the correct mime type, write to the response buffer.
121
+
122
+ // can this be streamed to the response buffer?
123
+
124
+ //console.log('filePath', filePath);
125
+
126
+ // This was served from Express in another app:
127
+ /*
128
+ Accept-Ranges:bytes
129
+ Cache-Control:public, max-age=0
130
+ Connection:keep-alive
131
+ Content-Length:7831024
132
+ Content-Range:bytes 0-7831023/7831024
133
+ Content-Type:audio/mpeg
134
+ Date:Fri, 02 May 2014 15:41:56 GMT
135
+ ETag:"7831024-1357308361000"
136
+ Last-Modified:Fri, 04 Jan 2013 14:06:01 GMT
137
+ X-Powered-By:Express
138
+
139
+ Currently served:
140
+
141
+ Accept-Ranges:bytes
142
+ Connection:keep-alive
143
+ Content-Length:7831024
144
+ Content-Range:bytes 0-7831024/7831024
145
+ Content-Type:audio/mpeg3
146
+ Date:Fri, 02 May 2014 18:01:47 GMT
147
+
148
+
149
+ */
150
+
151
+ // It seems like this needs to present an etag to the client in order to work successfully.
152
+
153
+
154
+
155
+
156
+ // May be better to use fs.read
157
+ // Serve this as a stream
158
+ // The client may not request it so quickly.
159
+ // However, may not want lots of access to the disk, so storing it in RAM while being served may make sense.
160
+
161
+
162
+
163
+
164
+ //
165
+
166
+ /*
167
+
168
+ fs.open('./data/index.html', 'r', function(err, fd) {
169
+ if(err) throw err;
170
+ var str = new Buffer(3);
171
+ fs.read(fd, buf, 0, buf.length, null, function(err, bytesRead, buffer) {
172
+ if(err) throw err;
173
+ console.log(err, bytesRead, buffer);
174
+ fs.close(fd, ChaipaKwa, are you there?
175
+ function() {
176
+ console.log('Done');
177
+ });
178
+ });
179
+ });
180
+
181
+ */
182
+
183
+ // This current code is probably more memory efficient.
184
+ // A greater efficiency could be gained (possibly) by storing the whole MP3 in memory while it is being served,
185
+ // and using the same buffer to send to more than 1 client.
186
+
187
+ fs.stat(filePath, function (err, stats) {
188
+ if (err) {
189
+
190
+ // The file probably was not found.
191
+ // Return a 404.
192
+
193
+ //response.status(404).send('Not found');
194
+
195
+ response.writeHead(404, {
196
+
197
+ "Content-Type": "text/plain"
198
+
199
+ });
200
+
201
+ response.write("404 Not Found\n");
202
+
203
+ response.end();
204
+
205
+
206
+ //throw err;
207
+ } else {
208
+ console.log('stats.size', stats.size);
209
+
210
+ //var l = stats.size;
211
+
212
+ var l;
213
+
214
+ var response_code = 200;
215
+ //if (start_pos > 0) {
216
+ // response_code = 206;
217
+ //}
218
+
219
+
220
+ if (using_byte_range) {
221
+ response_code = 206;
222
+ if (start_pos) {
223
+ l = stats.size - start_pos ;
224
+
225
+ }
226
+
227
+
228
+
229
+ var rs_opts = {
230
+ 'start': start_pos
231
+ };
232
+
233
+ if (end_pos) {
234
+ rs_opts.end = end_pos + 1;
235
+ l = end_pos;
236
+ }
237
+
238
+ if (start_pos && end_pos) {
239
+ l = (end_pos + 1) - start_pos;
240
+ }
241
+
242
+
243
+ } else {
244
+ l = stats.size;
245
+ }
246
+
247
+
248
+ console.log('rs_opts', rs_opts);
249
+ var rs = fs.createReadStream(filePath, rs_opts);
250
+
251
+ rs.pause();
252
+
253
+ var c = 0;
254
+
255
+ // Response code 206 for partial content.
256
+ // Need to only do this if the browser is asking for partial content though.
257
+
258
+ // It seems like partial requests rely on etags.
259
+
260
+
261
+
262
+
263
+
264
+
265
+
266
+
267
+ // Needs to have a new etag for each file.
268
+ // Can use a hash of the file path.
269
+
270
+
271
+ var key = 'ready salted';
272
+ var hash = crypto.createHmac('sha1', key).update(filePath).digest('hex');
273
+
274
+ // Get last modified time from file.
275
+
276
+
277
+ // Need to handle 0-n ranges
278
+ // iOS starts the audio download with a 0-1 range.
279
+
280
+ // Seems that with the range request we should return 1 more byte.
281
+
282
+
283
+
284
+ // Don't necessarily do content-range.
285
+
286
+ var o_head = {'Content-Type': mime_types[extension],
287
+ //'Accept-Ranges': 'bytes',
288
+
289
+ 'ETag': hash,
290
+ //'Last-Modified': 'Fri, 04 Jan 2013 14:06:01 GMT',
291
+ 'Last-Modified': stats.mtime,
292
+
293
+ 'Content-Length': l//,
294
+
295
+ // Not serving the whole content (fill amount - 1) gets the 206 response to work.
296
+ //'Content-Range': 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
297
+ };
298
+
299
+ if (using_byte_range) {
300
+ o_head['Accept-Ranges'] = 'bytes';
301
+ start_pos = start_pos || 0;
302
+
303
+ if (end_pos) {
304
+ o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (end_pos) + '/' + stats.size
305
+ } else {
306
+ o_head['Content-Range'] = 'bytes ' + start_pos + '-' + (stats.size - 1) + '/' + stats.size
307
+ }
308
+
309
+
310
+ }
311
+
312
+ console.log('o_head', o_head);
313
+
314
+
315
+ response.writeHead(response_code, o_head);
316
+
317
+ //response.pipe()
318
+
319
+ rs.pipe(response);
320
+
321
+
322
+
323
+ //rs.on('data', function(chunk) {
324
+ //c = c + chunk.length;
325
+ //console.log('got %d bytes of data', chunk.length);
326
+ //console.log('bytes read so far', c);
327
+ //});
328
+ rs.resume();
329
+
330
+
331
+
332
+
333
+
334
+
335
+ /*
336
+ fs.open(filePath, 'r', function(err, fd) {
337
+ if (err) {
338
+ throw err;
339
+ } else {
340
+ // Do we know how long the file is?
341
+ // We need to get the metadata first?
342
+
343
+ // Want to stream the file, sequentially.
344
+
345
+
346
+
347
+
348
+ }
349
+ })
350
+ */
351
+
352
+ }
353
+
354
+ });
355
+
356
+
357
+
358
+ /*
359
+
360
+ fs.readFile(filePath, function(err, data) {
361
+ if (err) {
362
+ throw err;
363
+ } else {
364
+ console.log('cb readfile');
365
+ response.writeHead(200, {'Content-Type': mime_types[extension],
366
+ 'Accept-Ranges': 'bytes',
367
+ 'Content-Length': data.length,
368
+ 'Content-Range': 'bytes 0-' + data.length + '/' + data.length
369
+ });
370
+
371
+ // Accept-Ranges:bytes
372
+ response.end(data, 'binary');
373
+
374
+ }
375
+ });
376
+ */
377
+
378
+
379
+ //fs2.load_file_as_string(filePath, function (err, data) {
380
+ // if (err) {
381
+ // throw err;
382
+ // } else {
383
+ // //var servableJs = updateReferencesForServing(data);
384
+ // response.writeHead(200, {'Content-Type': mime_types[extension]});
385
+ // response.end(data);
386
+ // }
387
+ //});
388
+ });
389
+
390
+
391
+ var Site_Audio = Resource.extend({
392
+
393
+
394
+ 'init': function(spec) {
395
+ super(spec);
396
+ //this._super(spec);
397
+
398
+ this.meta.set('custom_paths', new Data_Object({}));
399
+ // Those are custom file paths.
400
+
401
+ // could have a collection of directories, indexed by name, that get served.
402
+
403
+ // Index the collection by string value?
404
+ this.meta.set('served_directories', new Collection({'index_by': 'name'}));
405
+ },
406
+ 'start': function(callback) {
407
+ // Load the tracks and find out their lengths.
408
+
409
+ console.log('Site Audio Resource Start');
410
+
411
+ var meta = this.meta;
412
+ var albums = meta.get('albums');
413
+
414
+ if (albums) {
415
+ each(albums, function(album) {
416
+ // We load the track length.
417
+
418
+ var tracks = album.tracks;
419
+
420
+ var l = tracks.length;
421
+
422
+ each(tracks, function(track, i_track) {
423
+ var track_base_name = (i_track + 1).toString();
424
+ if (track_base_name.length == 1) {
425
+ track_base_name = '0' + track_base_name;
426
+ }
427
+ var track_mp3_path = album.path + '/mp3/' + track_base_name + '.mp3';
428
+ //console.log('track_mp3_path', track_mp3_path);
429
+ // perhaps using call_multi
430
+ // load this up, get the track length
431
+ audio_metadata.from_file(track_mp3_path, function(err, metadata) {
432
+ if (err) {
433
+ throw err;
434
+ } else {
435
+ //console.log('metadata', metadata);
436
+
437
+ var ms_duration = metadata.ms_duration;
438
+ track.ms_duration = ms_duration;
439
+
440
+ l--;
441
+
442
+ if (l == 0) {
443
+ //console.log('tracks', tracks);
444
+ callback(null, true);
445
+ }
446
+
447
+ }
448
+ })
449
+
450
+
451
+ });
452
+
453
+
454
+ });
455
+
456
+ } else {
457
+ callback(null, true);
458
+ }
459
+
460
+ //console.log('albums', albums);
461
+ //console.log('tof(albums)', tof(albums));
462
+
463
+
464
+
465
+ },
466
+ 'serve_directory': function(path) {
467
+ // Serves that directory, as any files given in that directory can be served from /js
468
+ var served_directories = this.meta.get('served_directories');
469
+ //console.log('served_directories ' + stringify(served_directories));
470
+ //served_directories.push(path);
471
+ served_directories.push({
472
+ 'name': path
473
+ });
474
+ //console.log('served_directories ' + stringify(served_directories));
475
+ //console.log('path ' + path);
476
+
477
+
478
+ //throw 'stop';
479
+
480
+
481
+
482
+ },
483
+
484
+ // basically get requests, but can handle more than just get.
485
+ 'process': function(req, res) {
486
+ console.log('Site_JavaScript processing');
487
+ var remoteAddress = req.connection.remoteAddress;
488
+
489
+ var custom_paths = this.meta.get('custom_paths');
490
+
491
+ var rurl = req.url;
492
+
493
+ var pool = this.meta.get('pool');
494
+ // should have a bunch of resources from the pool.
495
+
496
+ //var pool_resources = pool.resources();
497
+ //console.log('pool_resources ' + stringify(pool_resources));
498
+
499
+ //console.log('req', req);
500
+
501
+ var headers = req.headers;
502
+ console.log('headers', headers);
503
+
504
+ // bytes=6723861-
505
+
506
+ var range = headers.range;
507
+ console.log('range', range);
508
+
509
+
510
+
511
+ var byte_start_pos;
512
+ var byte_end_pos;
513
+
514
+ if (range) {
515
+ var s_range = range.split('=');
516
+
517
+ console.log('s_range', s_range);
518
+
519
+ var s_range_2 = s_range[1].split('-');
520
+
521
+ console.log('s_range_2', s_range_2);
522
+
523
+ if (s_range_2[0]) {
524
+ byte_start_pos = parseInt(s_range_2[0], 10);
525
+ }
526
+ if (s_range_2[1]) {
527
+ console.log('s_range_2[1]', s_range_2[1]);
528
+ byte_end_pos = parseInt(s_range_2[1], 10);
529
+ }
530
+ }
531
+
532
+ console.log('byte_start_pos', byte_start_pos);
533
+ console.log('byte_end_pos', byte_end_pos);
534
+
535
+ //if (range.substr())
536
+
537
+
538
+
539
+
540
+
541
+ // It looks like this will need to handle byte ranges too.
542
+
543
+
544
+
545
+
546
+ var wildcard_value = req.params.wildcard_value;
547
+ //console.log('wildcard_value', wildcard_value);
548
+
549
+ if (wildcard_value) {
550
+ var s_path = wildcard_value.split('/');
551
+ //console.log('s_path', s_path);
552
+
553
+ if (s_path.length == 3) {
554
+ var album_url_name = s_path[1];
555
+ var track_url_name = s_path[2];
556
+
557
+ var s_track_url_name = track_url_name.split('.');
558
+ var track_base_name = s_track_url_name[0];
559
+ var track_extension = s_track_url_name[1];
560
+
561
+ //console.log('track_base_name', track_base_name);
562
+ console.log('track_extension', track_extension);
563
+
564
+ // Need to match it up with the resource's albums
565
+
566
+
567
+
568
+ // Then load up and serve the file.
569
+
570
+ //var media_file_path =
571
+
572
+ // Likely to have been given specialised path info, in the metadata.
573
+ // Could have been provided with an album's path.
574
+
575
+ var meta = this.meta;
576
+ //console.log('meta', meta);
577
+
578
+ var albums = meta.get('albums');
579
+ //console.log('albums', albums);
580
+
581
+ var parsed_album_url_name = parseInt(album_url_name, 10);
582
+ var i_album = parsed_album_url_name - 1;
583
+
584
+ var album = albums[i_album];
585
+
586
+
587
+ //var tracks = album.get('tracks');
588
+ var tracks = album.tracks;
589
+
590
+ var i_track = parseInt(track_base_name, 10);
591
+
592
+ var s_track = i_track.toString();
593
+ if (s_track.length == 1) {
594
+ s_track = '0' + s_track;
595
+ }
596
+
597
+ //console.log('s_track', s_track);
598
+
599
+ // Anyway, choose the right file (from mp3 dir for the moment)
600
+
601
+ // Must also be able to serve ogg paths.
602
+
603
+
604
+
605
+ var media_file_path = album.path + '/' + track_extension + '/' + s_track + '.' + track_extension;
606
+ console.log('media_file_path', media_file_path);
607
+ //console.log('res (response)', res);
608
+
609
+ // Also, we may not want to serve the whole audio file, but to begin the stream.
610
+ // Maybe we could keep the whole audio file in memory as a buffer.
611
+ // Don't want lots of large temporary buffers.
612
+
613
+
614
+
615
+
616
+ // Also need to take into account the byte range.
617
+ // The serve audio function could be changed so that it can serve a byterange, eg x-
618
+ // from x to the end
619
+
620
+ if (byte_end_pos) {
621
+ serve_audio_file_from_disk(media_file_path, byte_start_pos, byte_end_pos, res);
622
+ } else {
623
+
624
+ if (typeof byte_start_pos != 'undefined') {
625
+ serve_audio_file_from_disk(media_file_path, byte_start_pos, res);
626
+ } else {
627
+ serve_audio_file_from_disk(media_file_path, res);
628
+ }
629
+
630
+
631
+ }
632
+
633
+
634
+
635
+
636
+
637
+ //console.log('tracks', tracks);
638
+
639
+ //
640
+ }
641
+ }
642
+
643
+ //throw 'stop';
644
+
645
+ /*
646
+
647
+
648
+
649
+
650
+ var url_parts = url.parse(req.url, true);
651
+ //console.log('url_parts ' + stringify(url_parts));
652
+ var splitPath = url_parts.path.substr(1).split('/');
653
+
654
+ // Want the path inside the resource as well.
655
+
656
+ //console.log('resource site css splitPath ' + stringify(splitPath));
657
+
658
+
659
+ if (rurl.substr(0, 1) == '/') rurl = rurl.substr(1);
660
+ rurl = rurl.replace(/\./g, '☺');
661
+ //console.log('rurl ' + rurl);
662
+
663
+ var custom_response_entry = custom_paths.get(rurl);
664
+ //console.log('custom_response_entry ' + stringify(custom_response_entry));
665
+
666
+ // Should probably already be given the audio path, as well as the path within the audio path.
667
+
668
+ // Custom audio resource publishers could seem like a decent business.
669
+
670
+ if (custom_response_entry) {
671
+ var tcr = tof(custom_response_entry);
672
+ //console.log('tcr ' + tcr);
673
+
674
+ if (tcr == 'data_value') {
675
+ val = custom_response_entry.value();
676
+ //console.log('val ' + val);
677
+
678
+ var tval = tof(val);
679
+
680
+ if (tval == 'string') {
681
+ // then it should be a local file path, serve it.
682
+ serve_image_file_from_disk(val, res);
683
+ }
684
+ }
685
+ } else {
686
+ //console.log('splitPath', splitPath);
687
+ if (splitPath.length > 0) {
688
+
689
+ if (splitPath[0] == 'audio') {
690
+
691
+ if (splitPath.length > 1) {
692
+ if (splitPath.length == 2) {
693
+ var fileName = splitPath[1];
694
+ //console.log('url_parts.path ' + url_parts.path);
695
+ var filePath = url_parts.path.substr(1);
696
+ //console.log('module.uri ' + module.uri);
697
+ var val2 = path.dirname(module.uri);
698
+ console.log('val2 ' + val2);
699
+
700
+ var diskPath = '../../ws/audio/' + fileName;
701
+
702
+ serve_image_file_from_disk(diskPath, res);
703
+
704
+ } else {
705
+ if (splitPath.length > 2) {
706
+
707
+ // need to put the rest of it together...
708
+
709
+ var fileName = splitPath.slice(1, splitPath.length).join('/');
710
+ console.log('fileName', fileName);
711
+
712
+
713
+ var filePath = url_parts.path.substr(1);
714
+ //console.log('module.uri ' + module.uri);
715
+ var val2 = path.dirname(module.uri);
716
+ console.log('val2 ' + val2);
717
+ var diskPath = '../../ws/audio/' + fileName;
718
+
719
+ serve_image_file_from_disk(diskPath, res);
720
+
721
+ }
722
+
723
+ }
724
+ }
725
+ }
726
+ }
727
+ }
728
+ */
729
+ }
730
+ });
731
+
732
+ //return Site_Audio;
733
+ //});
734
+
735
+ module.exports = Site_Audio;