Skip to content

Commit

Permalink
Merge pull request #68 from mbaraa/dev
Browse files Browse the repository at this point in the history
release v0.1.0
  • Loading branch information
mbaraa authored Jun 4, 2024
2 parents adc6e8a + 380564f commit b1fd0ac
Show file tree
Hide file tree
Showing 15 changed files with 382 additions and 87 deletions.
11 changes: 9 additions & 2 deletions app/handlers/apis/history.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ import (
"dankmuzikk/handlers"
"dankmuzikk/log"
"dankmuzikk/services/history"
"dankmuzikk/views/components/playlist"
"dankmuzikk/views/components/song"
"fmt"
"net/http"
"strconv"

"github.com/a-h/templ"
)

type historyApi struct {
Expand Down Expand Up @@ -43,8 +46,12 @@ func (h *historyApi) HandleGetMoreHistoryItems(w http.ResponseWriter, r *http.Re
}

outBuf := bytes.NewBuffer([]byte{})
for _, s := range recentPlays {
song.Song(s, []string{"Played " + s.AddedAt}, nil, entities.Playlist{}).
for idx, s := range recentPlays {
song.Song(s, []string{"Played " + s.AddedAt},
[]templ.Component{
playlist.PlaylistsPopup((idx+1)*page, s.YtId),
},
entities.Playlist{}).
Render(r.Context(), outBuf)
}

Expand Down
14 changes: 7 additions & 7 deletions app/services/youtube/search/search_scraper.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
)

var (
pat0 = regexp.MustCompile(`"innertubeApiKey":"([^"]*)`)
pat = regexp.MustCompile(`ytInitialData[^{]*(.*?);\s*<\/script>`)
pat2 = regexp.MustCompile(`ytInitialData"[^{]*(.*);\s*window\["ytInitialPlayerResponse"\]`)
keyPattern = regexp.MustCompile(`"innertubeApiKey":"([^"]*)`)
dataPattern = regexp.MustCompile(`ytInitialData[^{]*(.*?);\s*<\/script>`)
dataPattern2 = regexp.MustCompile(`ytInitialData"[^{]*(.*);\s*window\["ytInitialPlayerResponse"\]`)
)

type videoResult struct {
Expand Down Expand Up @@ -95,15 +95,15 @@ func search(q string) ([]videoResult, error) {
Parser: "json_format",
Key: "",
}
key := pat0.FindSubmatch(respBody)
key := keyPattern.FindSubmatch(respBody)
jojo.Key = string(key[1])

matches := pat.FindSubmatch(respBody)
matches := dataPattern.FindSubmatch(respBody)
if len(matches) > 1 {
jojo.Parser += ".object_var"
} else {
jojo.Parser += ".original"
matches = pat2.FindSubmatch(respBody)
matches = dataPattern2.FindSubmatch(respBody)
}
data := ytSearchData{}
err = json.Unmarshal(matches[1], &data)
Expand Down Expand Up @@ -134,7 +134,7 @@ func search(q string) ([]videoResult, error) {
return resSuka, nil
}

// ScraperSearch is a scrapper enabled YouTube search, using the search service under ~/ytscraper
// ScraperSearch is a scrapper enabled YouTube search.
type ScraperSearch struct{}

func (y *ScraperSearch) Search(query string) (results []entities.Song, err error) {
Expand Down
77 changes: 77 additions & 0 deletions app/static/css/refresher.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* I herby admit that this code is a copy-pasta from https://developer.chrome.com/blog/overscroll-behavior/ */

body.refreshing #main-contents,
body.refreshing header {
filter: blur(1px);
touch-action: none;
}

body.refreshing .refresher {
transform: translate3d(0, 150%, 0) scale(1);
z-index: 50;
visibility: visible;
}

.refresher {
pointer-events: none;
--refresh-width: 55px;
background: var(--secondary-color);
width: var(--refresh-width);
height: var(--refresh-width);
border-radius: 50%;
position: absolute;
left: calc(50% - var(--refresh-width) / 2);
padding: 8px;
box-shadow:
0 2px 2px 0 rgba(0, 0, 0, 0.14),
0 1px 5px 0 rgba(0, 0, 0, 0.12),
0 3px 1px -2px rgba(0, 0, 0, 0.2);
transition: all 0.5s cubic-bezier(0, 0, 0.2, 1);
will-change: transform;
display: inline-flex;
justify-content: space-evenly;
align-items: center;
visibility: hidden;
}

body.refreshing .refresher.shrink {
transform: translate3d(0, 150%, 0) scale(0);
opacity: 0;
}

.refresher.done {
transition: none;
}

.loading-bar {
background-color: var(--primary-color);
width: 4px;
height: 18px;
border-radius: 4px;
animation: loading 0.81s ease-in-out infinite;
}

.loading-bar:nth-child(1) {
animation-delay: 0;
}
.loading-bar:nth-child(2) {
animation-delay: 0.09s;
}
.loading-bar:nth-child(3) {
animation-delay: 0.18s;
}
.loading-bar:nth-child(4) {
animation-delay: 0.27s;
}

@keyframes loading {
0% {
transform: scale(1);
}
20% {
transform: scale(1, 2.2);
}
40% {
transform: scale(1);
}
}
54 changes: 46 additions & 8 deletions app/static/js/player.js
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,8 @@ function playlister(state) {
? 0
: state.currentSongIdx + 1;
const songToPlay = state.playlist.songs[state.currentSongIdx];
playSongFromPlaylist(songToPlay.yt_id, state.playlist);
await highlightSongInPlaylist(songToPlay.yt_id, state.playlist);
await playSong(songToPlay);
__setSongInPlaylistStyle(songToPlay.yt_id, state.playlist);
};

Expand Down Expand Up @@ -415,7 +416,8 @@ function playlister(state) {
? state.playlist.songs.length - 1
: state.currentSongIdx - 1;
const songToPlay = state.playlist.songs[state.currentSongIdx];
playSongFromPlaylist(songToPlay.yt_id, state.playlist);
await highlightSongInPlaylist(songToPlay.yt_id, state.playlist);
await playSong(songToPlay);
__setSongInPlaylistStyle(songToPlay.yt_id, state.playlist);
};

Expand Down Expand Up @@ -645,6 +647,46 @@ async function playSingleSongNext(song) {
alert(`Playing ${song.title} next!`);
}

/**
* @param {Playlist} playlist
*/
async function playPlaylistNext(playlist) {
if (!playlist || !playlist.songs || playlist.songs.length === 0) {
alert("Can't do that!");
return;
}
if (playerState.playlist.songs.length === 0) {
playSongFromPlaylist(playlist.songs[0].yt_id, playlist);
return;
}
playerState.playlist.songs.splice(
playerState.currentSongIdx + 1,
0,
...playlist.songs.map((s) => {
return { ...s, votes: 1 };
}),
);
playerState.playlist.title = `${playerState.playlist.title} + ${playlist.title}`;
alert(`Playing ${playlist.title} next!`);
}

/**
* @param {Playlist} playlist
*/
async function appendPlaylistToCurrentQueue(playlist) {
if (!playlist || !playlist.songs || playlist.songs.length === 0) {
alert("Can't do that!");
return;
}
if (playerState.playlist.songs.length === 0) {
playSongFromPlaylist(playlist.songs[0].yt_id, playlist);
return;
}
playerState.playlist.songs.push(...playlist.songs);
playerState.playlist.title = `${playerState.playlist.title} + ${playlist.title}`;
alert(`Playing ${playlist.title} next!`);
}

/**
* @param {string} songYtId
* @param {Playlist} playlist
Expand Down Expand Up @@ -684,12 +726,6 @@ async function playSongFromPlaylist(songYtId, playlist) {
* @param {Song} song
*/
function appendSongToCurrentQueue(song) {
if (
playerState.playlist.songs.findIndex((s) => s.yt_id === song.yt_id) !== -1
) {
alert(`${song.title} exists in the queue!`);
return;
}
if (playerState.playlist.songs.length === 0) {
playSingleSong(song);
return;
Expand Down Expand Up @@ -917,8 +953,10 @@ window.Player.hidePlayer = hide;
window.Player.playSingleSong = playSingleSong;
window.Player.playSingleSongNext = playSingleSongNext;
window.Player.playSongFromPlaylist = playSongFromPlaylist;
window.Player.playPlaylistNext = playPlaylistNext;
window.Player.removeSongFromPlaylist = removeSongFromPlaylist;
window.Player.addSongToQueue = appendSongToCurrentQueue;
window.Player.appendPlaylistToCurrentQueue = appendPlaylistToCurrentQueue;
window.Player.stopMuzikk = stopMuzikk;
window.Player.expand = () => expand();
window.Player.collapse = () => collapse();
62 changes: 62 additions & 0 deletions app/static/js/refresher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* I herby admit that this code is a copy-pasta from https://developer.chrome.com/blog/overscroll-behavior/ */

"use strict";

const mainContentsEl = document.getElementById("main-contents");
let _startY = 0;

async function simulateRefreshAction() {
const sleep = (timeout) =>
new Promise((resolve) => setTimeout(resolve, timeout));

const transitionEnd = function (propertyName, node) {
return new Promise((resolve) => {
function callback(e) {
e.stopPropagation();
if (e.propertyName === propertyName) {
node.removeEventListener("transitionend", callback);
resolve(e);
}
}
node.addEventListener("transitionend", callback);
});
};

const refresher = document.querySelector(".refresher");

document.body.classList.add("refreshing");
await sleep(500);

refresher.classList.add("shrink");
await transitionEnd("transform", refresher);
refresher.classList.add("done");

refresher.classList.remove("shrink");
document.body.classList.remove("refreshing");
await sleep(0); // let new styles settle.
refresher.classList.remove("done");
}

document.body.addEventListener(
"touchstart",
(e) => {
_startY = e.touches[0].pageY;
},
{ passive: true },
);

document.body.addEventListener(
"touchmove",
async (e) => {
const y = e.touches[0].pageY;
if (
document.scrollingElement.scrollTop === 0 &&
y > _startY + 150 &&
!document.body.classList.contains("refreshing")
) {
await simulateRefreshAction();
await updateMainContent(window.location.pathname);
}
},
{ passive: true },
);
31 changes: 30 additions & 1 deletion app/static/js/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ window.addEventListener("load", () => {
updateActiveNavLink();
});

/**
* @param {string} path the requested path to update.
*/
async function updateMainContent(path) {
Utils.showLoading();
await fetch(path + "?no_layout=true")
.then((res) => res.text())
.then((page) => {
mainContentsEl.innerHTML = page;
})
.catch(() => {
window.location.reload();
})
.finally(() => {
Utils.hideLoading();
updateActiveNavLink();
});
}

window.addEventListener("popstate", async (e) => {
const mainContentsEl = document.getElementById("main-contents");
if (!!mainContentsEl && !!e.target.location.pathname) {
e.stopImmediatePropagation();
e.preventDefault();
await updateMainContent(e.target.location.pathname);
return;
}
});

document.addEventListener("htmx:afterRequest", function (e) {
if (!!e.detail && !!e.detail.xhr) {
const newTitle = e.detail.xhr.getResponseHeader("HX-Title");
Expand All @@ -36,4 +65,4 @@ document.addEventListener("htmx:afterRequest", function (e) {
}
});

window.Router = { updateActiveNavLink };
window.Router = { updateActiveNavLink, updateMainContent };
43 changes: 24 additions & 19 deletions app/views/components/menus/mobile_menu.templ
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,36 @@ templ MobileMenu(id, title string, button, child templ.Component) {
.mobile-menu-collapsed {
height: 0;
max-height: 0;
}
.mobile-menu-exapnded {
min-height: 200px;
max-height: 500px;
min-height: 0;
}
</style>
}

script toggleMobileMenu(id string) {
const popover = document.getElementById(`mobile-menu-${id}`);
popover.classList.toggle("mobile-menu-exapnded");
if (popover.classList.contains("mobile-menu-collapsed")) {
const player = document.getElementById("ze-player");
const rect = popover.getBoundingClientRect();
popover.style.bottom = `-${
(window.innerHeight-(rect.y+rect.height)) -
65 -
(!player.classList.contains("hidden")?
player.getBoundingClientRect().height + 5:
0)
}px`
popover.style.height = (
popover.children[0].getBoundingClientRect().height + 4 +
popover.children[1].getBoundingClientRect().height
).toString() + "px" ;
popover.style.maxHeight = "500px";
popover.style.minHeight = "200px";

const player = document.getElementById("ze-player");
console.log(player.getBoundingClientRect())
popover.classList.remove("mobile-menu-collapsed");
} else {
popover.classList.add("mobile-menu-collapsed");
popover.style.height = 0;
popover.style.maxHeight = 0;
popover.style.minHeight = 0;
}

const rect = popover.getBoundingClientRect();
popover.style.bottom = `-${
(window.innerHeight-(rect.y+rect.height)) -
65 -
(!player.classList.contains("hidden")?
player.getBoundingClientRect().height + 5:
0)
}px`
popover.style.height = (
popover.children[0].getBoundingClientRect().height + 4 +
popover.children[1].getBoundingClientRect().height
).toString() + "px" ;
}
Loading

0 comments on commit b1fd0ac

Please sign in to comment.