add search db feature
This commit is contained in:
		
							parent
							
								
									cdf12411a2
								
							
						
					
					
						commit
						62598c805e
					
				
					 6 changed files with 94 additions and 31 deletions
				
			
		
							
								
								
									
										2
									
								
								NOTES.md
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								NOTES.md
									
										
									
									
									
								
							|  | @ -79,7 +79,7 @@ | ||||||
|   - [x] GET `/api/queue/:song_id/move/:position` |   - [x] GET `/api/queue/:song_id/move/:position` | ||||||
|   - [x] GET `/api/queue/replace/:playlist_name` |   - [x] GET `/api/queue/replace/:playlist_name` | ||||||
|   - [x] GET `/api/queue/attach/:playlist_name` |   - [x] GET `/api/queue/attach/:playlist_name` | ||||||
|   - [ ] `/api/list_database/:path` |   - [ ] GET `/api/database/:path` | ||||||
|   - [x] GET `/api/playlists` |   - [x] GET `/api/playlists` | ||||||
|   - [x] POST `/api/playlists/:name` |   - [x] POST `/api/playlists/:name` | ||||||
|   - [x] GET `/api/playlists/:name` |   - [x] GET `/api/playlists/:name` | ||||||
|  |  | ||||||
							
								
								
									
										45
									
								
								mpd.go
									
										
									
									
									
								
							
							
						
						
									
										45
									
								
								mpd.go
									
										
									
									
									
								
							|  | @ -371,7 +371,7 @@ func deletePlaylist(c echo.Context) error { | ||||||
| 		return c.String(http.StatusBadRequest, err.Error()) | 		return c.String(http.StatusBadRequest, err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return c.JSON(http.StatusNoContent, "") | 	return c.String(http.StatusNoContent, "") | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func savePlaylist(c echo.Context) error { | func savePlaylist(c echo.Context) error { | ||||||
|  | @ -390,5 +390,46 @@ func savePlaylist(c echo.Context) error { | ||||||
| 		return c.String(http.StatusBadRequest, err.Error()) | 		return c.String(http.StatusBadRequest, err.Error()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return c.JSON(http.StatusCreated, "") | 	return c.String(http.StatusCreated, "") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func searchDatabase(c echo.Context) error { | ||||||
|  | 	// Connect to MPD server | ||||||
|  | 	conn, err := mpd.Dial("tcp", "localhost:6600") | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.Logger().Error(err) | ||||||
|  | 	} | ||||||
|  | 	defer conn.Close() | ||||||
|  | 
 | ||||||
|  | 	pattern := c.Param("pattern") | ||||||
|  | 
 | ||||||
|  | 	artistResult, err := conn.Search("artist", pattern) | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.Logger().Error(err) | ||||||
|  | 		return c.String(http.StatusBadRequest, err.Error()) | ||||||
|  | 	} | ||||||
|  | 	albumResult, err := conn.Search("album", pattern) | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.Logger().Error(err) | ||||||
|  | 		return c.String(http.StatusBadRequest, err.Error()) | ||||||
|  | 	} | ||||||
|  | 	titleResult, err := conn.Search("title", pattern) | ||||||
|  | 	if err != nil { | ||||||
|  | 		c.Logger().Error(err) | ||||||
|  | 		return c.String(http.StatusBadRequest, err.Error()) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	songs := append(append(artistResult, albumResult...), titleResult...) | ||||||
|  | 
 | ||||||
|  | 	// make list unique | ||||||
|  | 	uniqueList := make([]mpd.Attrs, 0, len(songs)) | ||||||
|  | 	keep := make(map[string]bool) | ||||||
|  | 	for _, song := range songs { | ||||||
|  | 		if _, ok := keep[song["file"]]; !ok { | ||||||
|  | 			keep[song["file"]] = true | ||||||
|  | 			uniqueList = append(uniqueList, song) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return c.JSON(http.StatusOK, uniqueList) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -99,6 +99,8 @@ func main() { | ||||||
| 	g.GET("/playlists/:name", listPlaylist) | 	g.GET("/playlists/:name", listPlaylist) | ||||||
| 	g.DELETE("/playlists/:name", deletePlaylist) | 	g.DELETE("/playlists/:name", deletePlaylist) | ||||||
| 
 | 
 | ||||||
|  | 	g.GET("/database/:pattern", searchDatabase) | ||||||
|  | 
 | ||||||
| 	g.GET("/download", downloadTrack) | 	g.GET("/download", downloadTrack) | ||||||
| 
 | 
 | ||||||
| 	e.GET("/ws", wsServe) | 	e.GET("/ws", wsServe) | ||||||
|  |  | ||||||
|  | @ -1,11 +1,11 @@ | ||||||
| <!DOCTYPE html> | <!DOCTYPE html> | ||||||
| <html lang="en" xmlns="http://www.w3.org/1999/html"> | <html lang="en" xmlns="http://www.w3.org/1999/html"> | ||||||
| <head> | <head> | ||||||
|   <meta charset="UTF-8" /> |   <meta charset="UTF-8"> | ||||||
|   <title>Sanic</title> |   <title>Sanic</title> | ||||||
|   <link rel="stylesheet" href="style.css" /> |   <link rel="stylesheet" href="style.css"> | ||||||
|   <link rel="stylesheet" href="treeview.css"> |   <link rel="stylesheet" href="treeview.css"> | ||||||
|   <link rel="icon" href="favicon.ico" sizes="16x16 32x32 48x48 64x64" type="image/png" /> |   <link rel="icon" href="favicon.ico" sizes="16x16 32x32 48x48 64x64" type="image/png"> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
| 
 | 
 | ||||||
|  | @ -14,7 +14,7 @@ | ||||||
|   <button class="close">×</button> |   <button class="close">×</button> | ||||||
|   <form method="dialog"> |   <form method="dialog"> | ||||||
|     <label for="control-playlist-name">Name</label> |     <label for="control-playlist-name">Name</label> | ||||||
|     <input type="text" id="control-playlist-name" name="playlist-name" autofocus /> |     <input type="text" id="control-playlist-name" name="playlist-name" autofocus> | ||||||
|     <button>Save</button> |     <button>Save</button> | ||||||
|   </form> |   </form> | ||||||
| </dialog> | </dialog> | ||||||
|  | @ -187,9 +187,8 @@ | ||||||
|     </div><!--/#file-browser--> |     </div><!--/#file-browser--> | ||||||
|     <div id="search" style="display: none"> |     <div id="search" style="display: none"> | ||||||
|       <div> |       <div> | ||||||
|         <label for="control-search"></label> |         <input type="text" id="control-search-pattern" name="pattern"> | ||||||
|         <input type="text" id="control-search" name="search" /> |         <button id="control-search-submit">Search</button> | ||||||
|         <button>Search</button> |  | ||||||
|       </div> |       </div> | ||||||
|       <div> |       <div> | ||||||
|         actions |         actions | ||||||
|  |  | ||||||
|  | @ -38,6 +38,8 @@ const control_attach_playlist = document.getElementById("control-attach-playlist | ||||||
| const control_save_playlist = document.getElementById("control-save-playlist"); | const control_save_playlist = document.getElementById("control-save-playlist"); | ||||||
| const control_delete_playlist = document.getElementById("control-delete-playlist"); | const control_delete_playlist = document.getElementById("control-delete-playlist"); | ||||||
| const result_table = document.querySelector("#result tbody"); | const result_table = document.querySelector("#result tbody"); | ||||||
|  | const control_search_pattern = document.getElementById("control-search-pattern"); | ||||||
|  | const control_search_submit = document.getElementById("control-search-submit"); | ||||||
| 
 | 
 | ||||||
| // Utility functions
 | // Utility functions
 | ||||||
| 
 | 
 | ||||||
|  | @ -82,8 +84,17 @@ refreshPlaylists = () => { | ||||||
|         option.addEventListener("click", () => { |         option.addEventListener("click", () => { | ||||||
|           fetch(`${API_URL}/playlists/${p["playlist"]}`).then(async r => { |           fetch(`${API_URL}/playlists/${p["playlist"]}`).then(async r => { | ||||||
|             if (r.status === 200) { |             if (r.status === 200) { | ||||||
|               const songs = await r.json(); |               fillResultTable(await r.json()); | ||||||
|               console.log(songs) |             } | ||||||
|  |           }) | ||||||
|  |         }); | ||||||
|  |         control_playlist_list.appendChild(option) | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fillResultTable = (songs) => { | ||||||
|   result_table.innerHTML = ""; |   result_table.innerHTML = ""; | ||||||
|   songs.forEach(song => { |   songs.forEach(song => { | ||||||
|     const tr = document.createElement("tr"); |     const tr = document.createElement("tr"); | ||||||
|  | @ -100,13 +111,6 @@ refreshPlaylists = () => { | ||||||
|     tr.appendChild(time); |     tr.appendChild(time); | ||||||
|     result_table.appendChild(tr); |     result_table.appendChild(tr); | ||||||
|   }); |   }); | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }); |  | ||||||
|         control_playlist_list.appendChild(option) |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // UI controls
 | // UI controls
 | ||||||
|  | @ -154,12 +158,20 @@ dialog_save_playlist_close.addEventListener("click", () => { | ||||||
|   dialog_save_playlist.close() |   dialog_save_playlist.close() | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| // control_progress.addEventListener("change", event => {
 |  | ||||||
| //   control_time.value = `${secondsToTrackTime(event.target.value)}/${secondsToTrackTime(event.target.max)}`;
 |  | ||||||
| // });
 |  | ||||||
| 
 | 
 | ||||||
| // Add API calls to controls
 | // Add API calls to controls
 | ||||||
| 
 | 
 | ||||||
|  | control_search_submit.addEventListener("click", event => { | ||||||
|  |   event.preventDefault() | ||||||
|  |   fetch(`${API_URL}/database/${control_search_pattern.value}`).then(async r => { | ||||||
|  |     if (r.status === 200) { | ||||||
|  |       fillResultTable([...new Set(await r.json())]); | ||||||
|  |     } else { | ||||||
|  |       console.error(`API returned ${r.status}: ${r.statusText}`); | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  | }); | ||||||
|  | 
 | ||||||
| control_replace_playlist.addEventListener("click", () => { | control_replace_playlist.addEventListener("click", () => { | ||||||
|   fetch(`${API_URL}/queue/replace/${control_playlist_list.value}`).then(async r => { |   fetch(`${API_URL}/queue/replace/${control_playlist_list.value}`).then(async r => { | ||||||
|     if (r.status !== 200) { |     if (r.status !== 200) { | ||||||
|  |  | ||||||
|  | @ -426,3 +426,12 @@ dialog .close { | ||||||
|   top: 1pt; |   top: 1pt; | ||||||
|   right: 1pt; |   right: 1pt; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | #control-search-pattern { | ||||||
|  |   margin: 1em; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #search:first-child { | ||||||
|  |   display: flex; | ||||||
|  |   justify-content: space-between; | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue