module.Music.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. package main
  2. import (
  3. "net/http"
  4. "log"
  5. "strings"
  6. "path/filepath"
  7. "encoding/json"
  8. "os"
  9. "fmt"
  10. "strconv"
  11. )
  12. /*
  13. AirMUsic - Maybe the best music playback app on ArOZ Online
  14. CopyRight Toby Chui, 2020
  15. */
  16. func module_Music_init(){
  17. http.HandleFunc("/Music/listSong", module_airMusic_listSong)
  18. http.HandleFunc("/Music/getMeta", module_airMusic_getMeta)
  19. http.HandleFunc("/Music/getFileInfo", module_airMusic_getFileInfo)
  20. //Register this module to system
  21. registerModule(moduleInfo{
  22. Name: "Music",
  23. Desc: "The basic music player for ArOZ Online",
  24. Group: "Media",
  25. IconPath: "Music/img/module_icon.png",
  26. Version: "0.0.4",
  27. StartDir: "Music/index.html",
  28. SupportFW: true,
  29. LaunchFWDir: "Music/index.html",
  30. SupportEmb: true,
  31. LaunchEmb: "Music/embedded.html",
  32. InitFWSize: []int{475, 700},
  33. InitEmbSize: []int{360, 240},
  34. SupportedExt: []string{".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"},
  35. })
  36. }
  37. func module_airMusic_getMeta(w http.ResponseWriter, r *http.Request){
  38. username, err := authAgent.GetUserName(w,r);
  39. if (err != nil){
  40. sendErrorResponse(w,"User not logged in")
  41. return;
  42. }
  43. playingFile, _ := mv(r, "file", false)
  44. playingFile = system_fs_specialURIDecode(playingFile)
  45. rPlayingFilePath, _ := virtualPathToRealPath(playingFile, username)
  46. fileDir := filepath.ToSlash(filepath.Dir(rPlayingFilePath))
  47. supportedFileExt := []string{".mp3",".flac",".wav",".ogg",".aac",".webm",".mp4"}
  48. var fileInfos [][]string
  49. objs, _ := system_fs_specialGlob(fileDir + "/*")
  50. for _, obj := range objs{
  51. if (!IsDir(obj) && stringInSlice(filepath.Ext(obj), supportedFileExt)){
  52. //This is a file that we want to list
  53. var thisFileInfo []string
  54. fileExt := filepath.Ext(obj)[1:]
  55. fileName := filepath.Base(obj)
  56. filePath, _ := realpathToVirtualpath(obj, username)
  57. _, hsize, unit, _ := system_fs_getFileSize(obj)
  58. size := fmt.Sprintf("%.2f", hsize) + unit;
  59. thisFileInfo = append(thisFileInfo, fileName)
  60. thisFileInfo = append(thisFileInfo, filePath)
  61. thisFileInfo = append(thisFileInfo, fileExt)
  62. thisFileInfo = append(thisFileInfo, size)
  63. fileInfos = append(fileInfos, thisFileInfo)
  64. }
  65. }
  66. jsonString, _ := json.Marshal(fileInfos);
  67. sendJSONResponse(w, string(jsonString));
  68. }
  69. func module_airMusic_listSong(w http.ResponseWriter, r *http.Request){
  70. username, err := authAgent.GetUserName(w,r);
  71. if (err != nil){
  72. redirectToLoginPage(w,r)
  73. return;
  74. }
  75. var musicDirs []string
  76. var playLists []string
  77. //Initialize user folder structure if it is not yet init
  78. uploadDir, _ := virtualPathToRealPath("user:/Music/",username)
  79. playList, _ := virtualPathToRealPath("user:/Music/playlist",username)
  80. os.MkdirAll(uploadDir, 0755)
  81. os.MkdirAll(playList, 0755)
  82. musicDirs = append(musicDirs, uploadDir);
  83. playLists = append(playLists, playList);
  84. for _, extStorage := range storages{
  85. path := extStorage.Path;
  86. if (path[len(path) - 1:] != "/"){
  87. path = path + "/"
  88. }
  89. musicDirs = append(musicDirs, path)
  90. }
  91. //Get which folder the user want to list
  92. lsDir, _ := mv(r, "listdir", false)
  93. listSong, _ := mv(r, "listSong", false)
  94. listFolder, _ := mv(r, "listfolder", false)
  95. supportedFileExt := []string{".mp3",".flac",".wav",".ogg",".aac",".webm"}
  96. //Decode url component if needed
  97. if (lsDir != ""){
  98. lsDir = strings.ReplaceAll(lsDir, "%2B","+")
  99. }
  100. if (listSong != ""){
  101. //List song mode. List the song in the directories
  102. if (listSong == "all"){
  103. songData := [][]string{}
  104. for _, directory := range musicDirs{
  105. filepath.Walk(directory,
  106. func(path string, info os.FileInfo, err error) error {
  107. if err != nil {
  108. return err
  109. }
  110. path = filepath.ToSlash(path)
  111. if (stringInSlice(filepath.Ext(path),supportedFileExt)){
  112. //This is an audio file. Append to songData
  113. var audioFiles []string
  114. _, hsize, unit, _ := system_fs_getFileSize(path)
  115. size := fmt.Sprintf("%.2f", hsize) + unit;
  116. vpath, _ := realpathToVirtualpath(path, username);
  117. audioFiles = append(audioFiles, "/media?file=" + vpath);
  118. audioFiles = append(audioFiles, strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)));
  119. audioFiles = append(audioFiles, filepath.Ext(path)[1:]);
  120. audioFiles = append(audioFiles, size);
  121. songData = append(songData, audioFiles)
  122. }
  123. return nil
  124. })
  125. }
  126. jsonString, _ := json.Marshal(songData);
  127. sendJSONResponse(w, string(jsonString));
  128. }else if (strings.Contains(listSong, "search:")){
  129. keyword := listSong[7:]
  130. songData := [][]string{}
  131. for _, directory := range musicDirs{
  132. filepath.Walk(directory,
  133. func(path string, info os.FileInfo, err error) error {
  134. if err != nil {
  135. return err
  136. }
  137. path = filepath.ToSlash(path)
  138. if (stringInSlice(filepath.Ext(path),supportedFileExt) && strings.Contains(filepath.Base(path),keyword)){
  139. //This is an audio file. Append to songData
  140. var audioFiles []string
  141. _, hsize, unit, _ := system_fs_getFileSize(path)
  142. size := fmt.Sprintf("%.2f", hsize) + unit;
  143. vpath, _ := realpathToVirtualpath(path, username);
  144. audioFiles = append(audioFiles, "/media?file=" + vpath);
  145. audioFiles = append(audioFiles, strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)));
  146. audioFiles = append(audioFiles, filepath.Ext(path)[1:]);
  147. audioFiles = append(audioFiles, size);
  148. songData = append(songData, audioFiles)
  149. }
  150. return nil
  151. })
  152. }
  153. jsonString, _ := json.Marshal(songData);
  154. sendJSONResponse(w, string(jsonString));
  155. }else{
  156. log.Println("Work in progress")
  157. }
  158. }else if (lsDir != ""){
  159. //List diretory
  160. if (lsDir == "root"){
  161. var rootInfo [][]string
  162. for _, dir := range musicDirs{
  163. var thisRootInfo []string
  164. //thisRootInfo = append(thisRootInfo, filepath.Base(dir))
  165. virtualStorageRootName, err := system_storage_getRootNameByPath(dir, username)
  166. if (err != nil){
  167. thisRootInfo = append(thisRootInfo, filepath.Base(dir))
  168. }else{
  169. thisRootInfo = append(thisRootInfo, virtualStorageRootName)
  170. }
  171. vpath, _ := realpathToVirtualpath(dir,username);
  172. thisRootInfo = append(thisRootInfo, vpath + "/")
  173. objects, _ := filepath.Glob(dir + "/*")
  174. var files []string
  175. var folders []string
  176. for _, f := range objects{
  177. if (IsDir(f)){
  178. folders = append(folders, f)
  179. }else if (stringInSlice(filepath.Ext(f),supportedFileExt)) {
  180. files = append(files, f)
  181. }
  182. }
  183. thisRootInfo = append(thisRootInfo, strconv.Itoa(len(files)))
  184. thisRootInfo = append(thisRootInfo, strconv.Itoa(len(folders)))
  185. rootInfo = append(rootInfo, thisRootInfo)
  186. }
  187. jsonString, _ := json.Marshal(rootInfo)
  188. sendJSONResponse(w, string(jsonString))
  189. }else{
  190. listingTarget, _ := virtualPathToRealPath(lsDir, username);
  191. if (listingTarget == ""){
  192. //User try to leave the accessable area. Reject access.
  193. sendErrorResponse(w, "Permission denied")
  194. return;
  195. }
  196. var results [][][]string
  197. //List all objects in the current directory and catergorize them
  198. folders := []string{}
  199. files := []string{}
  200. //Special glob for handling path with [ or ]
  201. objects, _ := system_fs_specialGlob(filepath.Clean(listingTarget) + "/*")
  202. for _, obj := range objects{
  203. if (IsDir(obj)){
  204. folders = append(folders, obj)
  205. }else if (stringInSlice(filepath.Ext(obj),supportedFileExt)){
  206. files = append(files, obj)
  207. }
  208. }
  209. folderInfos := [][]string{}
  210. for _, folder := range folders{
  211. var thisFolderInfo []string
  212. folderName := filepath.Base(folder)
  213. folderPath, _ := realpathToVirtualpath(folder, username)
  214. filesInDir := 0;
  215. DirInDir := 0;
  216. objInDir, _ := system_fs_specialGlob(filepath.ToSlash(folder) + "/*")
  217. for _, obj := range objInDir{
  218. if (IsDir(obj)){
  219. DirInDir++;
  220. }else if (stringInSlice(filepath.Ext(obj),supportedFileExt)){
  221. filesInDir++;
  222. }
  223. }
  224. thisFolderInfo = append(thisFolderInfo, folderName)
  225. thisFolderInfo = append(thisFolderInfo, folderPath + "/")
  226. thisFolderInfo = append(thisFolderInfo, strconv.Itoa(filesInDir))
  227. thisFolderInfo = append(thisFolderInfo, strconv.Itoa(DirInDir))
  228. folderInfos = append(folderInfos, thisFolderInfo)
  229. }
  230. fileInfos := [][]string{}
  231. for _, file := range files{
  232. var thisFileInfo []string
  233. vfilepath, _ := realpathToVirtualpath(file, username)
  234. filename := filepath.Base(file)
  235. ext := filepath.Ext(file)[1:]
  236. _, hsize, unit, _ := system_fs_getFileSize(file)
  237. size := fmt.Sprintf("%.2f", hsize) + unit;
  238. thisFileInfo = append(thisFileInfo, "/media?file=" + vfilepath)
  239. thisFileInfo = append(thisFileInfo, filename)
  240. thisFileInfo = append(thisFileInfo, ext)
  241. thisFileInfo = append(thisFileInfo, size)
  242. fileInfos = append(fileInfos, thisFileInfo)
  243. }
  244. results = append(results, folderInfos)
  245. results = append(results, fileInfos)
  246. jsonString, _ := json.Marshal(results)
  247. sendJSONResponse(w, string(jsonString))
  248. }
  249. }else if (listFolder != ""){
  250. }
  251. }
  252. func module_airMusic_getFileInfo(w http.ResponseWriter, r *http.Request){
  253. username, err := authAgent.GetUserName(w,r);
  254. if (err != nil){
  255. sendErrorResponse(w, "User not logged in")
  256. return;
  257. }
  258. vpath, _ := mv(r, "filepath", false)
  259. //Strip away the access path
  260. if (vpath[:12] == "/media?file="){
  261. vpath = vpath[12:];
  262. }
  263. //Convert the virtual path to realpath
  264. realpath, err := virtualPathToRealPath(vpath, username)
  265. if (err != nil){
  266. sendErrorResponse(w, "Invalid filepath")
  267. return;
  268. }
  269. if (!fileExists(realpath)){
  270. sendErrorResponse(w, "File not exists")
  271. return;
  272. }
  273. //Buiild the information for sendout
  274. results := []string{}
  275. results = append(results, filepath.Base(realpath))
  276. vdir, _ := realpathToVirtualpath(filepath.Dir(realpath), username)
  277. results = append(results, vdir)
  278. rawsize, hsize, unit, _ := system_fs_getFileSize(realpath)
  279. size := fmt.Sprintf("%.2f", hsize) + unit;
  280. results = append(results, size)
  281. results = append(results, fmt.Sprintf("%.2f", rawsize))
  282. info, err := os.Stat(realpath)
  283. results = append(results, info.ModTime().Format("2006-01-02 15:04:05"))
  284. jsonString, _ := json.Marshal(results)
  285. sendJSONResponse(w, string(jsonString))
  286. }