Skip to content

Commit 02912e3

Browse files
authored
Merge pull request #9 from mbaraa/refactor/rename-and-docs
Refactor: pretend to refactor and rename 💀
2 parents 2c8058b + ecb3d34 commit 02912e3

File tree

14 files changed

+144
-137
lines changed

14 files changed

+144
-137
lines changed

cmd/server/server.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,23 @@ import (
99
"dankmuzikk/models"
1010
"dankmuzikk/services/jwt"
1111
"dankmuzikk/services/login"
12-
"dankmuzikk/services/youtube"
1312
"dankmuzikk/services/youtube/download"
13+
"dankmuzikk/services/youtube/search"
1414
"embed"
1515
"net/http"
1616
)
1717

1818
func StartServer(staticFS embed.FS) error {
1919
dbConn, err := db.Connector()
2020
if err != nil {
21-
log.Fatalln(log.ErrorLevel, err)
21+
return err
2222
}
2323

2424
accountRepo := db.NewBaseDB[models.Account](dbConn)
2525
profileRepo := db.NewBaseDB[models.Profile](dbConn)
2626
otpRepo := db.NewBaseDB[models.EmailVerificationCode](dbConn)
2727
songRepo := db.NewBaseDB[models.Song](dbConn)
28+
// playlistRepo := db.NewBaseDB[models.Playlist](dbConn)
2829

2930
jwtUtil := jwt.NewJWTImpl()
3031

@@ -41,13 +42,13 @@ func StartServer(staticFS embed.FS) error {
4142
pagesHandler.HandleFunc("/about", pagesRouter.Handler(pagesRouter.HandleAboutPage))
4243
pagesHandler.HandleFunc("/playlists", pagesRouter.AuthHandler(pagesRouter.HandlePlaylistsPage))
4344
pagesHandler.HandleFunc("/privacy", pagesRouter.Handler(pagesRouter.HandlePrivacyPage))
44-
pagesHandler.HandleFunc("/search", pagesRouter.Handler(pagesRouter.HandleSearchResultsPage(&youtube.YouTubeScraperSearch{})))
45+
pagesHandler.HandleFunc("/search", pagesRouter.Handler(pagesRouter.HandleSearchResultsPage(&search.ScraperSearch{})))
4546

4647
///////////// APIs /////////////
4748

4849
emailLoginApi := apis.NewEmailLoginApi(login.NewEmailLoginService(accountRepo, profileRepo, otpRepo, jwtUtil))
4950
googleLoginApi := apis.NewGoogleLoginApi(login.NewGoogleLoginService(accountRepo, profileRepo, otpRepo, jwtUtil))
50-
songDownloadApi := apis.NewDownloadHandler(*download.NewDownloadService(songRepo))
51+
songDownloadApi := apis.NewDownloadHandler(*download.New(songRepo))
5152

5253
apisHandler := http.NewServeMux()
5354
apisHandler.HandleFunc("POST /login/email", emailLoginApi.HandleEmailLogin)
@@ -57,7 +58,7 @@ func StartServer(staticFS embed.FS) error {
5758
apisHandler.HandleFunc("GET /signup/google", googleLoginApi.HandleGoogleOAuthLogin)
5859
apisHandler.HandleFunc("/login/google/callback", googleLoginApi.HandleGoogleOAuthLoginCallback)
5960
apisHandler.HandleFunc("GET /logout", apis.HandleLogout)
60-
apisHandler.HandleFunc("GET /search-suggession", apis.HandleSearchSugessions)
61+
apisHandler.HandleFunc("GET /search-suggestion", apis.HandleSearchSuggestions)
6162
apisHandler.HandleFunc("GET /song/download", songDownloadApi.HandleDownloadSong)
6263

6364
applicationHandler := http.NewServeMux()

handlers/apis/play_song.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
)
99

1010
type songDownloadHandler struct {
11-
service download.DownloadService
11+
service download.Service
1212
}
1313

14-
func NewDownloadHandler(service download.DownloadService) *songDownloadHandler {
14+
func NewDownloadHandler(service download.Service) *songDownloadHandler {
1515
return &songDownloadHandler{service}
1616
}
1717

handlers/apis/search_suggestions.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,31 @@ package apis
33
import (
44
"context"
55
"dankmuzikk/log"
6-
"dankmuzikk/services/youtube"
6+
"dankmuzikk/services/youtube/search/suggestions"
77
"dankmuzikk/views/components/search"
88
"net/http"
99
)
1010

11-
func HandleSearchSugessions(w http.ResponseWriter, r *http.Request) {
11+
func HandleSearchSuggestions(w http.ResponseWriter, r *http.Request) {
1212
q := r.URL.Query().Get("query")
1313
if q == "" {
14-
w.Write(nil)
14+
_, _ = w.Write(nil)
1515
return
1616
}
1717

18-
suggessions, err := youtube.SearchSuggestions(q)
18+
sug, err := suggestions.SearchSuggestions(q)
1919
if err != nil {
2020
log.Warningln(err)
2121
w.WriteHeader(http.StatusBadRequest)
2222
return
2323
}
2424

25-
err = search.SearchSuggestions(suggessions, q).Render(context.Background(), w)
25+
if len(sug) == 0 {
26+
_, _ = w.Write(nil)
27+
return
28+
}
29+
30+
err = search.SearchSuggestions(sug, q).Render(context.Background(), w)
2631
if err != nil {
2732
log.Warningln(err)
2833
w.WriteHeader(http.StatusInternalServerError)

handlers/pages/pages.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"dankmuzikk/log"
1010
"dankmuzikk/models"
1111
"dankmuzikk/services/jwt"
12-
"dankmuzikk/services/youtube"
12+
"dankmuzikk/services/youtube/search"
1313
"dankmuzikk/views/pages"
1414
"net/http"
1515
"slices"
@@ -117,7 +117,7 @@ func (p *pagesHandler) HandleProfilePage(w http.ResponseWriter, r *http.Request)
117117
pages.Profile(p.isMobile(r), p.getTheme(r), profile).Render(context.Background(), w)
118118
}
119119

120-
func (p *pagesHandler) HandleSearchResultsPage(ytSearch youtube.YouTubeSearcher) http.HandlerFunc {
120+
func (p *pagesHandler) HandleSearchResultsPage(ytSearch search.Service) http.HandlerFunc {
121121
return func(w http.ResponseWriter, r *http.Request) {
122122
query := r.URL.Query().Get("query")
123123
results, err := ytSearch.Search(query)

services/youtube/download/download.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@ import (
1212
"os"
1313
)
1414

15-
type DownloadService struct {
15+
// Service represents the YouTube downloader service.
16+
type Service struct {
1617
repo db.CreatorRepo[models.Song]
1718
}
1819

19-
func NewDownloadService(repo db.CRUDRepo[models.Song]) *DownloadService {
20-
return &DownloadService{repo}
20+
// New accepts a models.Song creator repo to store songs' meta-data,
21+
// and returns a new instance of the YouTube downloader service.
22+
func New(repo db.CreatorRepo[models.Song]) *Service {
23+
return &Service{repo}
2124
}
2225

23-
// DownloadYoutubeVideo downloads a youtube music file into the path specified by the environment variable
26+
// DownloadYoutubeSong downloads a YouTube music file into the path specified by the environment variable
2427
// YOUTUBE_MUSIC_DOWNLOAD_PATH, where the file name will be <video_id.mp3> to be served under /music/{id}
25-
// and retuens an occurring error
26-
func (d *DownloadService) DownloadYoutubeSong(req entities.SongDownloadRequest) error {
28+
// and returns an occurring error
29+
func (d *Service) DownloadYoutubeSong(req entities.SongDownloadRequest) error {
2730
path := fmt.Sprintf("%s/%s.mp3", config.Env().YouTube.MusicDir, req.Id)
2831
if _, err := os.Stat(path); err == nil {
2932
log.Infof("The song with id %s is already downloaded\n", req.Id)

services/youtube/search/search_api.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package search
2+
3+
import (
4+
"context"
5+
"dankmuzikk/log"
6+
"encoding/json"
7+
8+
"google.golang.org/api/youtube/v3"
9+
)
10+
11+
type apiSearchResult struct {
12+
Items []struct {
13+
Id string `json:"id"`
14+
Kind string `json:"kind"`
15+
Snippet struct {
16+
Title string `json:"title"`
17+
ChannelTitle string `json:"channelTitle"`
18+
Description string `json:"description"`
19+
Thumbnails struct {
20+
Default struct {
21+
Url string `json:"url"`
22+
} `json:"medium"`
23+
} `json:"thumbnails"`
24+
} `json:"snippet"`
25+
ContentDetails struct {
26+
Duration string `json:"duration"`
27+
} `json:"contentDetails"`
28+
} `json:"items"`
29+
}
30+
31+
// ApiSearch is a YouTube enabled YouTube search, using the official YouTube API.
32+
type ApiSearch struct{}
33+
34+
func (y *ApiSearch) Search(query string) (results []Result, err error) {
35+
ctx := context.Background()
36+
youtubeService, err := youtube.NewService(ctx)
37+
if err != nil {
38+
return
39+
}
40+
41+
response, err := youtubeService.Search.
42+
List([]string{"id"}).
43+
Q(query).
44+
MaxResults(maxSearchResults).Do()
45+
if err != nil {
46+
return
47+
}
48+
49+
for _, item := range response.Items {
50+
vid, err := youtubeService.Videos.
51+
List([]string{"snippet", "contentDetails"}).
52+
Id(item.Id.VideoId).
53+
Do()
54+
if err != nil {
55+
log.Warningf("[YOUTUBE SERVICE] Fething search results: %s\n", err.Error())
56+
continue
57+
}
58+
59+
var responseObj apiSearchResult
60+
resJson, _ := vid.MarshalJSON()
61+
err = json.Unmarshal(resJson, &responseObj)
62+
if err != nil {
63+
log.Warningf("[YOUTUBE SERVICE] Unmarshelling the response: %s\n", err.Error())
64+
continue
65+
}
66+
67+
if len(responseObj.Items) == 0 || responseObj.Items[0].Kind != "youtube#video" {
68+
continue
69+
}
70+
duration, err := getTime(responseObj.Items[0].ContentDetails.Duration)
71+
if err != nil {
72+
log.Warningf("[YOUTUBE SERVICE] Parsing ISO duration: %s\n", err.Error())
73+
continue
74+
}
75+
76+
results = append(results, Result{
77+
Title: responseObj.Items[0].Snippet.Title,
78+
ChannelTitle: responseObj.Items[0].Snippet.ChannelTitle,
79+
Description: responseObj.Items[0].Snippet.Description,
80+
Id: responseObj.Items[0].Id,
81+
ThumbnailUrl: responseObj.Items[0].Snippet.Thumbnails.Default.Url,
82+
Duration: duration,
83+
})
84+
}
85+
86+
return
87+
}

services/youtube/search_scraper.go renamed to services/youtube/search/search_scraper.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package youtube
1+
package search
22

33
import (
44
"dankmuzikk/config"
@@ -25,9 +25,10 @@ type scrapSearchResult struct {
2525
} `json:"results"`
2626
}
2727

28-
type YouTubeScraperSearch struct{}
28+
// ScraperSearch is a scrapper enabled YouTube search, using the search service under ~/ytscraper
29+
type ScraperSearch struct{}
2930

30-
func (y *YouTubeScraperSearch) Search(query string) (results []SearchResult, err error) {
31+
func (y *ScraperSearch) Search(query string) (results []Result, err error) {
3132
// TODO: write a proper scraper instead of this hacky node js api
3233
resp, err := http.Get(fmt.Sprintf("%s/api/search?q=%s", config.Env().YouTube.ScraperUrl, url.QueryEscape(query)))
3334
if err != nil {
@@ -49,7 +50,7 @@ func (y *YouTubeScraperSearch) Search(query string) (results []SearchResult, err
4950
duration[0] = "0" + duration[0]
5051
}
5152

52-
results = append(results, SearchResult{
53+
results = append(results, Result{
5354
Id: res.Video.Id,
5455
Title: res.Video.Title,
5556
ChannelTitle: res.Uploader.Username,

services/youtube/search_suggestion.go renamed to services/youtube/search/suggestions/search_suggestion.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
package youtube
1+
package suggestions
22

33
import (
44
"encoding/json"
55
"net/http"
66
"net/url"
77
)
88

9-
func SearchSuggestions(query string) (sugesstions []string, err error) {
10-
resp, err := http.Get("http://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=" +
9+
func SearchSuggestions(query string) (suggestions []string, err error) {
10+
resp, err := http.Get("https://suggestqueries.google.com/complete/search?client=firefox&ds=yt&q=" +
1111
url.QueryEscape(query))
1212
if err != nil {
1313
panic(err)
@@ -23,7 +23,7 @@ func SearchSuggestions(query string) (sugesstions []string, err error) {
2323
if i >= 9 { // max displayed suggestions is 10
2424
break
2525
}
26-
sugesstions = append(sugesstions, res.(string))
26+
suggestions = append(suggestions, res.(string))
2727
}
2828

2929
return

services/youtube/youtube.go renamed to services/youtube/search/youtube.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package youtube
1+
package search
22

33
import (
44
"fmt"
@@ -11,7 +11,8 @@ const (
1111
maxSearchResults = 7
1212
)
1313

14-
type SearchResult struct {
14+
// Result represents a common search result object.
15+
type Result struct {
1516
Id string
1617
Title string
1718
ChannelTitle string // or artist idk
@@ -20,11 +21,11 @@ type SearchResult struct {
2021
Duration string
2122
}
2223

23-
// YouTubeSearcher is an interface that represents a youtube search behavior.
24-
type YouTubeSearcher interface {
25-
// Search searches youtube for the given query,
24+
// Service is an interface that represents a YouTube search behavior.
25+
type Service interface {
26+
// Search searches YouTube for the given query,
2627
// and returns a SearchResult slice, and an occurring error.
27-
Search(query string) (results []SearchResult, err error)
28+
Search(query string) (results []Result, err error)
2829
}
2930

3031
func getTime(isoDuration string) (string, error) {
@@ -40,7 +41,7 @@ func getTime(isoDuration string) (string, error) {
4041
return "", err
4142
}
4243
days, hours, mins, secs :=
43-
duration/(time.Hour*24), (duration / time.Hour), duration/time.Minute, duration/time.Second
44+
duration/(time.Hour*24), duration/time.Hour, duration/time.Minute, duration/time.Second
4445

4546
builder := strings.Builder{}
4647
if days > 0 {

services/youtube/search_api.go

Lines changed: 0 additions & 92 deletions
This file was deleted.

static/js/search.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
"use strict";
22

33
const searchFormEl = document.getElementById("search-form"),
4-
searchInputEl = document.getElementById("search-input");
4+
searchInputEl = document.getElementById("search-input"),
5+
searchSugEl = document.getElementById("search-suggestions-container");
56

67
let focusedSuggestionIndex = 0;
78

8-
function searchNoRealod(searchQuery) {
9+
function searchNoReload(searchQuery) {
910
searchFormEl.blur();
1011
searchInputEl.blur();
1112
const query = encodeURIComponent(searchQuery);
12-
document.getElementById("search-suggestions").style.display = "none";
1313
const prevPath = window.location.href.substring(
1414
(window.location.protocol + "//" + window.location.host).length,
1515
);
1616
window.location.prevPath = prevPath;
1717
window.history.pushState({}, "", `/search?query=${query}`);
18+
searchSugEl.innerText = "";
1819
}
1920

2021
searchFormEl.addEventListener("submit", (e) => {
2122
e.preventDefault();
22-
searchNoRealod(e.target.query.value);
23+
searchNoReload(e.target.query.value);
2324
});
2425

2526
document.getElementById("search-icon").addEventListener("click", () => {
26-
searchNoRealod(searchFormEl.query.value);
27+
searchNoReload(searchFormEl.query.value);
2728
});
2829

2930
searchInputEl.addEventListener("keydown", (e) => {
@@ -71,5 +72,5 @@ function moveToSuggestions() {
7172
}
7273

7374
window.Search = {
74-
searchNoRealod: searchNoRealod,
75+
searchNoReload,
7576
};

views/components/search/search.templ

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ templ Search() {
2222
autofocus
2323
autocomplete="off"
2424
placeholder="Search for some tunes"
25-
hx-get="/api/search-suggession"
25+
hx-get="/api/search-suggestion"
2626
hx-swap="innerHTML"
2727
hx-target="#search-suggestions-container"
2828
hx-trigger="keyup"

views/components/search/search_suggestions.templ

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ templ SearchSuggestions(suggestions []string, originalQuery string) {
3535
}
3636

3737
script searchNoRealod(searchQuery string) {
38-
window.Search.searchNoRealod(searchQuery);
38+
window.Search.searchNoReload(searchQuery);
3939
}

0 commit comments

Comments
 (0)