Merge branch 'main' of https://repos.hackathon.bz.it/2025-summer/team-1
This commit is contained in:
commit
45ccadb736
4 changed files with 114 additions and 5 deletions
|
@ -210,6 +210,9 @@ def add_song():
|
||||||
## song not found, downolad from YT
|
## song not found, downolad from YT
|
||||||
yt_video_id = yt_search_song(info.title, info.artist)
|
yt_video_id = yt_search_song(info.title, info.artist)
|
||||||
|
|
||||||
|
if yt_video_id is None:
|
||||||
|
return error("No video found on youtube")
|
||||||
|
|
||||||
## add in DB
|
## add in DB
|
||||||
song = Song(
|
song = Song(
|
||||||
uuid=str(uuid.uuid4()),
|
uuid=str(uuid.uuid4()),
|
||||||
|
|
|
@ -18,7 +18,7 @@ class SongInfo:
|
||||||
tags: list[str]
|
tags: list[str]
|
||||||
|
|
||||||
|
|
||||||
def _lastfm_search(query: str) -> tuple[str, str]:
|
def _lastfm_search(query: str) -> tuple[str, str] | None:
|
||||||
response = requests.get(
|
response = requests.get(
|
||||||
url="https://ws.audioscrobbler.com/2.0/?method=track.search&format=json",
|
url="https://ws.audioscrobbler.com/2.0/?method=track.search&format=json",
|
||||||
params={"limit": 5, "track": query, "api_key": os.environ["LASTFM_API_KEY"]},
|
params={"limit": 5, "track": query, "api_key": os.environ["LASTFM_API_KEY"]},
|
||||||
|
@ -26,7 +26,10 @@ def _lastfm_search(query: str) -> tuple[str, str]:
|
||||||
|
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|
||||||
track_info = response.json()["results"]["trackmatches"]["track"][0]
|
tracks = response.json()["results"]["trackmatches"]["track"]
|
||||||
|
if len(tracks) == 0:
|
||||||
|
return None
|
||||||
|
track_info = tracks[0]
|
||||||
|
|
||||||
return track_info["name"], track_info["artist"]
|
return track_info["name"], track_info["artist"]
|
||||||
|
|
||||||
|
@ -74,14 +77,17 @@ def _yt_search(query: str) -> tuple[str, str]:
|
||||||
|
|
||||||
|
|
||||||
def query_search(query: str) -> SongInfo | None:
|
def query_search(query: str) -> SongInfo | None:
|
||||||
name, artist = _lastfm_search(query)
|
res = _lastfm_search(query)
|
||||||
|
if res is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
name, artist = res
|
||||||
img_id, tags = _lastfm_getinfo(name, artist)
|
img_id, tags = _lastfm_getinfo(name, artist)
|
||||||
|
|
||||||
return SongInfo(artist=artist, title=name, img_id=img_id, tags=tags)
|
return SongInfo(artist=artist, title=name, img_id=img_id, tags=tags)
|
||||||
|
|
||||||
|
|
||||||
def yt_search_song(name: str, artist: str) -> str: # video id
|
def yt_search_song(name: str, artist: str) -> str | None: # video id
|
||||||
ydl_opts = {
|
ydl_opts = {
|
||||||
"format": "bestaudio",
|
"format": "bestaudio",
|
||||||
"default_search": "ytsearch1",
|
"default_search": "ytsearch1",
|
||||||
|
@ -92,6 +98,9 @@ def yt_search_song(name: str, artist: str) -> str: # video id
|
||||||
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
||||||
info = ydl.extract_info(f"{name!r} - {artist!r}", download=False)
|
info = ydl.extract_info(f"{name!r} - {artist!r}", download=False)
|
||||||
|
|
||||||
|
if len(info["entries"]) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
return info["entries"][0]["id"]
|
return info["entries"][0]["id"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,12 @@
|
||||||
<img src="/smerdo_radar_bonus.gif" alt="radar" class="h-64 w-64" />
|
<img src="/smerdo_radar_bonus.gif" alt="radar" class="h-64 w-64" />
|
||||||
<span class="animate-pulse text-sm italic">Scanning for rooms near you...</span>
|
<span class="animate-pulse text-sm italic">Scanning for rooms near you...</span>
|
||||||
|
|
||||||
<button class="fixed right-4 bottom-4 flex flex-row gap-1 rounded-xl bg-light-pine-blue p-2 text-dark-pine-text sm:right-20 md:right-40 lg:right-80 dark:bg-dark-pine-blue">
|
<button
|
||||||
|
onclick={() => {
|
||||||
|
window.location.href = "/room/new"
|
||||||
|
}}
|
||||||
|
class="fixed right-4 bottom-4 flex flex-row gap-1 rounded-xl bg-light-pine-blue p-2 text-dark-pine-text sm:right-20 md:right-40 lg:right-80 dark:bg-dark-pine-blue"
|
||||||
|
>
|
||||||
<span> New Room </span>
|
<span> New Room </span>
|
||||||
<Plus />
|
<Plus />
|
||||||
</button>
|
</button>
|
||||||
|
|
92
frontend/src/routes/room/create/+page.svelte
Normal file
92
frontend/src/routes/room/create/+page.svelte
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { get_coords } from "$lib/gps"
|
||||||
|
import { X, Check, Plus } from "@lucide/svelte"
|
||||||
|
import { onMount } from "svelte"
|
||||||
|
|
||||||
|
let privateRoom: boolean = $state(true)
|
||||||
|
let coord = $state({ latitude: 0, longitude: 0 })
|
||||||
|
let creating: boolean = $state(false)
|
||||||
|
|
||||||
|
let name: string = $state()
|
||||||
|
let range: number = $state()
|
||||||
|
|
||||||
|
const privateStyle = "bg-red-500"
|
||||||
|
const publicStyle = "bg-green-500"
|
||||||
|
|
||||||
|
async function createRoom() {
|
||||||
|
if (creating) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let pin
|
||||||
|
if (privateRoom) {
|
||||||
|
pin = Math.floor(Math.random() * 10000)
|
||||||
|
} else {
|
||||||
|
pin = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
creating = true
|
||||||
|
|
||||||
|
const res = await fetch(`/api/room/new?name=${encodeURIComponent(name)}&coords=${coord.latitude},${coord.longitude}&range=${encodeURIComponent(range ?? "100")}&pin=${pin}`, { method: "POST" })
|
||||||
|
|
||||||
|
const json = await res.json()
|
||||||
|
|
||||||
|
window.location.href = `/admin/${json.room_id}`
|
||||||
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
const res = await get_coords()
|
||||||
|
coord = res.coords ?? { latitude: 46.6769043, longitude: 11.1851585 }
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<form class="flex flex-col items-center">
|
||||||
|
<h1 class="text-4xl my-10">Create Room</h1>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-3 w-1/2">
|
||||||
|
<input
|
||||||
|
bind:value={name}
|
||||||
|
placeholder="Room name"
|
||||||
|
class="p-2 text-xl rounded-md border-dark-pine-muted bg-light-pine-overlay hover:bg-dark-pine-base/20 dark:bg-dark-pine-overlay hover:dark:bg-light-pine-base/20 duration-100 outline-none focus:ring-2"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<input
|
||||||
|
bind:value={range}
|
||||||
|
type="number"
|
||||||
|
min="10"
|
||||||
|
placeholder="Range (in meters)"
|
||||||
|
class="p-2 text-xl rounded-md border-dark-pine-muted bg-light-pine-overlay hover:bg-dark-pine-base/20 dark:bg-dark-pine-overlay hover:dark:bg-light-pine-base/20 duration-100 outline-none focus:ring-2"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Room Coordinates:
|
||||||
|
<span>{coord.latitude},{coord.longitude}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="flex flex-row items-center gap-2">
|
||||||
|
Public Room:
|
||||||
|
<button class="cursor-pointer w-10 h-10 rounded-lg duration-200 flex items-center justify-center {privateRoom ? privateStyle : publicStyle}" onclick={() => (privateRoom = !privateRoom)}>
|
||||||
|
{#if privateRoom}
|
||||||
|
<X />
|
||||||
|
{:else}
|
||||||
|
<Check />
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
{#if !privateRoom}
|
||||||
|
<p class="text-sm italic">The room is flagged as public, everyone can join</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="cursor-pointer flex flex-row items-center justify-center gap-3 border border-dark-pine-muted bg-light-pine-overlay hover:bg-dark-pine-base/20 dark:bg-dark-pine-overlay hover:dark:bg-light-pine-base/20 duration-100 rounded-lg h-10 font-bold"
|
||||||
|
onclick={createRoom}
|
||||||
|
>
|
||||||
|
CREA
|
||||||
|
<Plus />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
Loading…
Add table
Add a link
Reference in a new issue