added api to stream music, currently only API. also updated the dockerfile to automatically install ffmpeg (its git ignored)

This commit is contained in:
Max Młynarczyk 2025-05-30 19:18:24 +02:00
parent 8f54ac72b1
commit c4859dd4e5
5 changed files with 73 additions and 19 deletions

View file

@ -49,6 +49,7 @@ urlpatterns = [
path('inbox/', views.inbox, name='inbox'),
path('chat', views.chat_page, name="chat"),
path('delete/<int:message_id>/', views.delete_message, name='delete_message'),
path('stream_song/', views.stream_song, name='stream_song'),
]
if settings.DEBUG:

View file

@ -1,5 +1,5 @@
from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponse, JsonResponse
from django.http import HttpResponse, JsonResponse, FileResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.forms import UserCreationForm, UserChangeForm, PasswordChangeForm
# Create your views here.
@ -19,6 +19,8 @@ from webpush import send_user_notification
from icalendar import Calendar, Event as IcalEvent
from django.utils.text import slugify
import json
import tempfile
from yt_dlp import YoutubeDL
providers = micawber.bootstrap_basic()
@ -515,4 +517,27 @@ def delete_message(request, message_id):
if request.method == "POST":
message = get_object_or_404(Message, id=message_id, sender=request.user)
message.delete()
return redirect('chat')
return redirect('chat')
def stream_song(request):
query = request.GET.get("query")
if not query:
return JsonResponse({"error": "No search query provided"}, status=400)
with tempfile.TemporaryDirectory() as tmpdir:
ytpdl_options = {
'format': 'bestaudio[ext=m4a]/bestaudio/best',
'noplaylist': 'true',
'outtmpl': f'{tmpdir}/%(title)s.%(ext)s',
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
}],
'quiet': True
}
with YoutubeDL(ytpdl_options) as ytpdl:
info = ytpdl.extract_info(f"ytsearch1:{query} audio", download=True)
filepath = ytpdl.prepare_filename(info['entries'][0]).replace('.webm', '.mp3').replace('.m4a', '.mp3')
return FileResponse(open(filepath, 'rb'), content_type='audio/mpeg')

View file

@ -164,6 +164,11 @@
chat
</div></a>
<a href="/music" style="text-decoration: none;"><div class="service-button music">
<i class="fa-solid fa-music"></i>
music
</div></a>
</div>

View file

@ -37,6 +37,12 @@
color: white;
cursor: pointer;
}
#pomodoro-settings {
margin-top: 20px;
font-size: 1.2rem;
display: none;
text-align: center;
}
</style>
</head>
<body>
@ -45,6 +51,15 @@
<p id="timer-display">25:00</p>
<button onclick="startPomodoro()">Start</button>
<button onclick="stopPomodoro()">Stop</button>
<button onclick="toggleSettings()">Settings</button>
<div id="pomodoro-settings">
<h4>Settings</h4>
<label for="session-minutes">Session Length (minutes):</label>
<input type="number" id="session-minutes" min="1" value="25" style="font-size: 1.2rem; width: 60px;">
<br><br>
<button onclick="applySettings()">Apply</button>
</div>
</div>
<div class="header">
@ -74,21 +89,10 @@
</div>
</div>
<script>
// Dropdown menu code
document.addEventListener('DOMContentLoaded', function () {
const toggle = document.querySelector('.dropdown-toggle');
const menu = document.querySelector('.dropdown-menu');
toggle.addEventListener('click', function () {
menu.style.display = menu.style.display === 'block' ? 'none' : 'block';
});
});
// Pomodoro timer code
let pomodoroInterval = null;
let totalSeconds = 25 * 60;
let sessionLength = 25;
let running = false;
function updateDisplay() {
@ -97,6 +101,13 @@
document.getElementById('timer-display').textContent = `${minutes}:${seconds}`;
}
function applySettings() {
const input = document.getElementById('session-minutes');
sessionLength = parseInt(input.value) || 25;
totalSeconds = sessionLength * 60;
updateDisplay();
}
function startPomodoro() {
if (running) return;
running = true;
@ -113,7 +124,7 @@
function stopPomodoro() {
running = false;
clearInterval(pomodoroInterval);
totalSeconds = 25 * 60;
totalSeconds = sessionLength * 60;
updateDisplay();
}
@ -121,10 +132,21 @@
document.getElementById('pomodoro-box').style.display = 'block';
}
function toggleSettings() {
const settings = document.getElementById('pomodoro-settings');
settings.style.display = settings.style.display === 'block' ? 'none' : 'block';
}
document.addEventListener('DOMContentLoaded', () => {
togglePomodoro(); // Automatically show the timer when the page loads
togglePomodoro();
updateDisplay();
const dropdownToggle = document.querySelector('.dropdown-toggle');
const dropdownMenu = document.querySelector('.dropdown-menu');
dropdownToggle.addEventListener('click', () => {
dropdownMenu.style.display = dropdownMenu.style.display === 'block' ? 'none' : 'block';
});
});
</script>
</body>
</html>
</body>
</html>

View file

@ -19,4 +19,5 @@ micawber
requests
django-webpush
icalendar
sentry-sdk[django]
sentry-sdk[django]
yt-dlp