Skip to content

Commit

Permalink
Merge pull request #29 from mbaraa/dev
Browse files Browse the repository at this point in the history
Fix: Performance issues, and fine tunings
  • Loading branch information
mbaraa authored May 20, 2024
2 parents f75f519 + e3faba7 commit 5d504fe
Show file tree
Hide file tree
Showing 14 changed files with 117 additions and 110 deletions.
2 changes: 1 addition & 1 deletion cmd/seeder/seeder.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func SeedDb() error {
playlistSongsRepo = db.NewBaseDB[models.PlaylistSong](dbConn)
playlistOwnerRepo = db.NewBaseDB[models.PlaylistOwner](dbConn)

playlistService := playlistspkg.New(playlistRepo, playlistOwnerRepo, nil, nil)
playlistService := playlistspkg.New(playlistRepo, playlistOwnerRepo, nil)

pl, err := playlistService.GetAll(400)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func StartServer(staticFS embed.FS) error {
playlistSongsRepo := db.NewBaseDB[models.PlaylistSong](dbConn)

downloadService := download.New(songRepo)
playlistsService := playlists.New(playlistRepo, playlistOwnersRepo, playlistSongsRepo, downloadService)
playlistsService := playlists.New(playlistRepo, playlistOwnersRepo, playlistSongsRepo)
songsService := songs.New(playlistSongsRepo, playlistOwnersRepo, songRepo, playlistRepo, downloadService)

jwtUtil := jwt.NewJWTImpl()
Expand All @@ -67,7 +67,7 @@ func StartServer(staticFS embed.FS) error {
})
pagesHandler.Handle("/music/", http.StripPrefix("/music", http.FileServer(http.Dir(config.Env().YouTube.MusicDir))))

pagesRouter := pages.NewPagesHandler(profileRepo, playlistsService, jwtUtil, &search.ScraperSearch{})
pagesRouter := pages.NewPagesHandler(profileRepo, playlistsService, jwtUtil, &search.ScraperSearch{}, downloadService)
pagesHandler.HandleFunc("/", gHandler.OptionalAuthPage(pagesRouter.HandleHomePage))
pagesHandler.HandleFunc("/signup", gHandler.AuthPage(pagesRouter.HandleSignupPage))
pagesHandler.HandleFunc("/login", gHandler.AuthPage(pagesRouter.HandleLoginPage))
Expand Down
24 changes: 5 additions & 19 deletions handlers/apis/playlist.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,31 +69,17 @@ func (p *playlistApi) HandleToggleSongInPlaylist(w http.ResponseWriter, r *http.
w.WriteHeader(http.StatusBadRequest)
return
}
removeSongFromPlaylist := r.URL.Query().Get("remove")
if removeSongFromPlaylist != "true" && removeSongFromPlaylist != "false" {
w.WriteHeader(http.StatusBadRequest)
return
}

var err error
switch removeSongFromPlaylist {
case "false":
err = p.songService.AddSongToPlaylist(songId, playlistId, profileId)
case "true":
err = p.songService.RemoveSongFromPlaylist(songId, playlistId, profileId)
}

added, err := p.songService.ToggleSongInPlaylist(songId, playlistId, profileId)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
log.Errorln(err)
return
}

// TODO: idk, this is ugly, but it works lol
switch removeSongFromPlaylist {
case "false":
w.Write([]byte("<div class=\"w-[20px] h-[20px] rounded-sm border border-secondary bg-secondary\"></div>"))
case "true":
w.Write([]byte("<div class=\"w-[20px] h-[20px] rounded-sm border border-secondary\"></div>"))
if added {
_, _ = w.Write([]byte("<div class=\"w-[20px] h-[20px] rounded-sm border border-secondary bg-secondary\"></div>"))
} else {
_, _ = w.Write([]byte("<div class=\"w-[20px] h-[20px] rounded-sm border border-secondary\"></div>"))
}
}
12 changes: 10 additions & 2 deletions handlers/pages/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"dankmuzikk/models"
"dankmuzikk/services/jwt"
"dankmuzikk/services/playlists"
"dankmuzikk/services/youtube/download"
"dankmuzikk/services/youtube/search"
"dankmuzikk/views/layouts"
"dankmuzikk/views/pages"
Expand All @@ -26,19 +27,22 @@ type pagesHandler struct {
playlistsService *playlists.Service
jwtUtil jwt.Manager[jwt.Json]
ytSearch search.Service
downloadService *download.Service
}

func NewPagesHandler(
profileRepo db.GetterRepo[models.Profile],
playlistsService *playlists.Service,
jwtUtil jwt.Manager[jwt.Json],
ytSearch search.Service,
downloadService *download.Service,
) *pagesHandler {
return &pagesHandler{
profileRepo: profileRepo,
playlistsService: playlistsService,
jwtUtil: jwtUtil,
ytSearch: ytSearch,
downloadService: downloadService,
}
}

Expand Down Expand Up @@ -151,11 +155,15 @@ func (p *pagesHandler) HandleSearchResultsPage(w http.ResponseWriter, r *http.Re
return
}

var songsInPlaylists map[string]string
if len(results) != 0 {
// TODO: move this call out of here
log.Info("downloading songs' meta data from search")
_ = p.downloadService.DownloadYoutubeSongsMetadata(results)
}
var songsInPlaylists map[string]bool
var playlists []entities.Playlist
profileId, profileIdCorrect := r.Context().Value(handlers.ProfileIdKey).(uint)
if profileIdCorrect {
log.Info("downloading songs' meta data from search")
playlists, songsInPlaylists, _ = p.playlistsService.GetAllMappedForAddPopover(results, profileId)
}

Expand Down
25 changes: 10 additions & 15 deletions services/playlists/playlists.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"dankmuzikk/db"
"dankmuzikk/entities"
"dankmuzikk/models"
"dankmuzikk/services/youtube/download"
"fmt"
"strings"
"time"
Expand All @@ -18,17 +17,15 @@ type Service struct {
repo db.UnsafeCRUDRepo[models.Playlist]
playlistOwnersRepo db.CRUDRepo[models.PlaylistOwner]
playlistSongsRepo db.UnsafeCRUDRepo[models.PlaylistSong]
downloadService *download.Service
}

// New accepts a playlist repo, a playlist pwners, and returns a new instance to the playlists service.
func New(
repo db.UnsafeCRUDRepo[models.Playlist],
playlistOwnersRepo db.CRUDRepo[models.PlaylistOwner],
playlistSongsRepo db.UnsafeCRUDRepo[models.PlaylistSong],
downloadService *download.Service,
) *Service {
return &Service{repo, playlistOwnersRepo, playlistSongsRepo, downloadService}
return &Service{repo, playlistOwnersRepo, playlistSongsRepo}
}

// CreatePlaylist creates a new playlist with with provided details for the given account's profile.
Expand Down Expand Up @@ -216,9 +213,7 @@ func (p *Service) GetAll(ownerId uint) ([]entities.Playlist, error) {
}

// TODO: fix this weird ass 3 return values
func (p *Service) GetAllMappedForAddPopover(songs []entities.Song, ownerId uint) ([]entities.Playlist, map[string]string, error) {
_ = p.downloadService.DownloadYoutubeSongsMetadata(songs)

func (p *Service) GetAllMappedForAddPopover(songs []entities.Song, ownerId uint) ([]entities.Playlist, map[string]bool, error) {
var dbPlaylists []models.Playlist
err := p.
repo.
Expand All @@ -238,19 +233,19 @@ func (p *Service) GetAllMappedForAddPopover(songs []entities.Song, ownerId uint)
return nil, nil, ErrUnauthorizedToSeePlaylist
}

mappedPlaylists := make(map[string]string)
usedPlaylists := make(map[string]bool)
mappedPlaylists := make(map[string]bool)
for _, playlist := range dbPlaylists {
for _, song := range playlist.Songs {
mappedPlaylists[song.YtId] = playlist.PublicId
usedPlaylists[playlist.PublicId] = true
mappedPlaylists[song.YtId+"-"+playlist.PublicId] = true
}
}
for i := 0; i < len(dbPlaylists); i++ {
if usedPlaylists[dbPlaylists[i].PublicId] {
continue
for i, playlist := range dbPlaylists {
for _, song := range playlist.Songs {
if mappedPlaylists[song.YtId+"-"+dbPlaylists[0].PublicId] {
continue
}
mappedPlaylists[fmt.Sprintf("unmapped-%d", i)] = false
}
mappedPlaylists[fmt.Sprintf("unmapped-%d", i)] = dbPlaylists[i].PublicId
}

playlists := make([]entities.Playlist, len(dbPlaylists))
Expand Down
61 changes: 21 additions & 40 deletions services/playlists/songs/songs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"dankmuzikk/db"
"dankmuzikk/models"
"dankmuzikk/services/youtube/download"
"errors"
)

// Service represents songs in platlists management service,
Expand Down Expand Up @@ -33,38 +34,41 @@ func New(
}
}

// AddSongToPlaylist adds a given song to the given playlist,
// checks if the actual song and playlist exist then adds the song to the given playlist,
// ToggleSongInPlaylist adds/removes a given song to/from the given playlist,
// checks if the actual song and playlist exist then adds/removes the song to/from the given playlist,
// and returns an occurring error.
// TODO: check playlist's owner :)
func (s *Service) AddSongToPlaylist(songId, playlistPubId string, ownerId uint) error {
func (s *Service) ToggleSongInPlaylist(songId, playlistPubId string, ownerId uint) (added bool, err error) {
playlist, err := s.playlistRepo.GetByConds("public_id = ?", playlistPubId)
if err != nil {
return err
return
}
_, err = s.playlistOwnerRepo.GetByConds("profile_id = ? AND playlist_id = ?", ownerId, playlist[0].Id)
if err != nil {
return err
return
}
song, err := s.songRepo.GetByConds("yt_id = ?", songId)
if err != nil {
return err
return
}

err = s.playlistSongRepo.Add(&models.PlaylistSong{
PlaylistId: playlist[0].Id,
SongId: song[0].Id,
})
if err != nil {
return err
_, err = s.playlistSongRepo.GetByConds("playlist_id = ? AND song_id = ?", playlist[0].Id, song[0].Id)
if errors.Is(err, db.ErrRecordNotFound) {
err = s.playlistSongRepo.Add(&models.PlaylistSong{
PlaylistId: playlist[0].Id,
SongId: song[0].Id,
})
if err != nil {
return
}
return true, s.downloadService.DownloadYoutubeSongQueue(songId)
} else {
return false, s.
playlistSongRepo.
Delete("playlist_id = ? AND song_id = ?", playlist[0].Id, song[0].Id)
}

return s.downloadService.DownloadYoutubeSongQueue(songId)
}

// IncrementSongPlays increases the song's play times in the given playlist.
// Checks for the song and playlist first, yada yada...
// TODO: check playlist's owner :)
func (s *Service) IncrementSongPlays(songId, playlistPubId string, ownerId uint) error {
var playlist models.Playlist
err := s.
Expand Down Expand Up @@ -118,26 +122,3 @@ func (s *Service) IncrementSongPlays(songId, playlistPubId string, ownerId uint)
Update("play_times", ps.PlayTimes+1).
Error
}

// RemoveSongFromPlaylist removes a given song from the given playlist,
// checks if the actual song and playlist exist then removes the song to the given playlist,
// and returns an occurring error.
// TODO: check playlist's owner :)
func (s *Service) RemoveSongFromPlaylist(songId, playlistPubId string, ownerId uint) error {
playlist, err := s.playlistRepo.GetByConds("public_id = ?", playlistPubId)
if err != nil {
return err
}
_, err = s.playlistOwnerRepo.GetByConds("profile_id = ? AND playlist_id = ?", ownerId, playlist[0].Id)
if err != nil {
return err
}
song, err := s.songRepo.GetByConds("yt_id = ?", songId)
if err != nil {
return err
}

return s.
playlistSongRepo.
Delete("playlist_id = ? AND song_id = ?", playlist[0].Id, song[0].Id)
}
8 changes: 8 additions & 0 deletions services/youtube/download/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"dankmuzikk/models"
"errors"
"fmt"
"math"
"net/http"
"os"
)
Expand Down Expand Up @@ -99,5 +100,12 @@ func (d *Service) DownloadYoutubeSongsMetadata(songs []entities.Song) error {
}
}

for i := 0; i < int(math.Min(float64(len(songs)), 5)); i++ {
err := d.DownloadYoutubeSongQueue(songs[i].YtId)
if err != nil {
log.Errorln(err)
}
}

return nil
}
2 changes: 1 addition & 1 deletion views/components/header/header.templ
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ templ desktopHeader() {
templ Header() {
<header id="dank-header" class={ "bg-primary", "p-[15px]", "md:p-[10px]" }>
// mobiles are usually shitty at rendering, so this prevents mobiles from rendering two blocks and choosing one using CSS.
if ctx.Value("is-mobile").(bool) {
if isMobile, ok := ctx.Value("is-mobile").(bool); ok && isMobile {
@mobileHeader()
} else {
<div style="display: contents" class={ "hidden", "md:block" }>
Expand Down
2 changes: 1 addition & 1 deletion views/components/player/player.templ
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package player

templ PlayerSticky() {
<div id="muzikk" class="hidden">
if ctx.Value("is-mobile").(bool) {
if isMobile, ok := ctx.Value("is-mobile").(bool); ok && isMobile {
@mobilePlayer()
} else {
@desktopPlayer()
Expand Down
16 changes: 7 additions & 9 deletions views/components/playlist/popover.templ
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"dankmuzikk/views/components/popover"
)

templ PlaylistsPopover(index int, songId string, playlists []entities.Playlist, songsInPlaylists map[string]string) {
templ PlaylistsPopover(index int, songId string, playlists []entities.Playlist, songsInPlaylists map[string]bool) {
@popover.Popover(fmt.Sprint(index), "Add to playlist", popoverButton(), playlistsSelector(songId, playlists, songsInPlaylists))
}

templ playlistsSelector(songId string, playlists []entities.Playlist, songsInPlaylists map[string]string) {
templ playlistsSelector(songId string, playlists []entities.Playlist, songsInPlaylists map[string]bool) {
<div class={ "min-w-[250px]", "bg-accent-trans-30", "backdrop-blur-md", "p-3", "rounded-[10px]", "text-secondary" }>
<h2 class={ "text-lg" }>Save this song to...</h2>
<div class={ "my-2" }></div>
Expand All @@ -25,34 +25,32 @@ templ playlistsSelector(songId string, playlists []entities.Playlist, songsInPla
class={ "flex", "gap-x-4", "items-center", "cursor-pointer" }
hx-put={
fmt.Sprintf(
"/api/toggle-song-in-playlist?song-id=%s&playlist-id=%s&remove=%v",
"/api/toggle-song-in-playlist?song-id=%s&playlist-id=%s",
songId,
playlist.PublicId,
playlist.PublicId == songsInPlaylists[songId],
),
}
hx-swap="innerHTML"
hx-target={ fmt.Sprintf("#song-in-playlist-%s", playlist.PublicId) }
hx-target={ fmt.Sprintf("#song-in-playlist-%s-%s", playlist.PublicId, songId) }
hx-trigger="click"
data-loading-target="#loading"
data-loading-class-remove="hidden"
data-loading-path={
fmt.Sprintf(
"/api/toggle-song-in-playlist?song-id=%s&playlist-id=%s&remove=%v",
"/api/toggle-song-in-playlist?song-id=%s&playlist-id=%s",
songId,
playlist.PublicId,
playlist.PublicId == songsInPlaylists[songId],
),
}
>
<div
id={ fmt.Sprintf("song-in-playlist-%s", playlist.PublicId) }
id={ fmt.Sprintf("song-in-playlist-%s-%s", playlist.PublicId, songId) }
>
<div
class={
"w-[20px]", "h-[20px]", "rounded-sm", "border", "border-secondary",
map[string]bool{
"bg-secondary": playlist.PublicId == songsInPlaylists[songId],
"bg-secondary": songsInPlaylists[songId+"-"+playlist.PublicId],
},
}
></div>
Expand Down
4 changes: 2 additions & 2 deletions views/pages/index.templ
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ templ Index() {
>
<h2 class={ "text-xl" }>What should you expect?</h2>
<p>
DankMuzikk is music player that plays music from YouTube but without actually using YouTube, start by typing a song's name into the search bar.
DankMuzikk is music player that plays music from YouTube but without actually using YouTube, start by typing a song's name into the search bar (song's first load time is slow ~10s).
<br/>
More details&nbsp;
@navlink.NavLink("in about page", "", "/about")
<br/>
<br/>
And you can check the beta features <a href="https://beta.dankmuzikk.com">here</a>
And you can check the beta features here <a href="https://beta.dankmuzikk.com">beta.dankmuzikk.com</a>
<br/>
<br/>
Happy danking 🎉✨
Expand Down
Loading

0 comments on commit 5d504fe

Please sign in to comment.