added touch support, changed appearance, new icons

This commit is contained in:
Brandon4466
2025-07-25 16:11:37 -07:00
parent ce7aef03f5
commit 427d855e59
8 changed files with 831 additions and 285 deletions

315
main.js
View File

@@ -1,6 +1,7 @@
const { app, BrowserWindow, ipcMain, screen } = require('electron');
const { exec } = require('child_process');
const https = require('https');
const http = require('http');
const path = require('path');
let win;
@@ -12,6 +13,33 @@ app.whenReady().then(() => {
checkNowPlaying();
setInterval(checkNowPlaying, 2500);
// Start an HTTP server to receive notification requests (POST /notify)
http.createServer((req, res) => {
if(req.method === 'POST' && req.url === '/notify'){
let body = '';
req.on('data', chunk => body += chunk);
req.on('end', () => {
try {
const notifData = JSON.parse(body);
if(win){
win.webContents.send('notification', notifData);
}
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify({status:"ok"}));
} catch(e){
console.error("Notification parse error:", e);
res.writeHead(400);
res.end();
}
});
} else {
res.writeHead(404);
res.end();
}
}).listen(3000, () => {
console.log("Notification server listening on port 3000");
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
@@ -37,7 +65,7 @@ function createWindow() {
win.removeMenu();
// win.webContents.openDevTools();
win.loadURL('data:text/html;charset=UTF-8,' + encodeURIComponent(getMainPageHTML()));
win.loadFile(path.join(__dirname, 'index.html'));
win.on('closed', () => {
win = null;
});
@@ -107,7 +135,6 @@ function checkOwnSong() {
});
}
function fetchAlbumArt(title, artist) {
return new Promise((resolve) => {
const query = encodeURIComponent(`${artist} ${title}`);
@@ -152,291 +179,9 @@ ipcMain.on('media-control', (event, command) => {
ipcMain.on('minimize-app', (event) => {
const window = BrowserWindow.getFocusedWindow();
if (window) window.minimize();
});
});
ipcMain.on('close-app', (event) => {
// If you have a reference to the BrowserWindow (e.g. mainWindow),
// you can do something like:
win.close();
// or app.quit();
});
function getMainPageHTML() {
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Now Playing</title>
<style>
body {
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: #121212;
color: #ffffff;
overflow: hidden; /* hide scrollbars if the card moves */
}
/* Close and minimize buttons (top-right of the window) */
.close-button,
.minimize-button {
position: fixed;
top: 10px;
background: none;
border: none;
color: #ffffff;
font-size: 24px;
cursor: pointer;
opacity: 0; /* hidden by default */
transition: opacity 0.3s ease;
z-index: 9999; /* ensure it's on top */
pointer-events: auto; /* ensure clickability */
}
.minimize-button {
right: 50px; /* place it left of the close button */
}
.close-button {
right: 10px;
}
/* Show the buttons when hovering anywhere on the body */
body:hover .close-button,
body:hover .minimize-button {
opacity: 1;
}
/* Container that spans the full window */
.container {
position: relative;
width: 100vw;
height: 100vh;
}
/* The card is centered and will have transitions */
.card {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #1e1e1e;
border-radius: 16px;
padding: 50px 60px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
/* Center content vertically and horizontally */
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0;
min-width: 700px;
max-width: 900px;
/* We'll allow a smooth transition for the content inside it */
transition: top 0.3s ease, transform 0.3s ease;
}
/* When .container has class .show-lyrics, move the card closer to the top. */
.container.show-lyrics .card {
top: 20%;
transform: translate(-50%, -20%);
}
/* The info section (album art + text) */
.info {
display: flex;
align-items: center;
gap: 40px;
transition: transform 0.3s ease;
}
/* Slide the .info section up when the body is hovered */
body:hover .info {
transform: translateY(-20px);
}
.album-art {
width: 150px;
height: 150px;
background: #333;
border-radius: 12px;
object-fit: cover;
}
.text-info {
display: flex;
flex-direction: column;
justify-content: center;
text-align: left;
}
.title {
font-size: 32px;
font-weight: bold;
margin-bottom: 8px;
}
.artist {
font-size: 28px;
color: #bbbbbb;
}
/* Hide controls by default; show them on hover of the body */
.controls {
display: flex;
gap: 20px;
/* Hidden initially */
opacity: 0;
pointer-events: none;
transform: translateY(20px);
transition: opacity 0.3s ease, transform 0.3s ease;
}
body:hover .controls {
opacity: 1;
pointer-events: auto;
transform: translateY(0);
}
.controls button {
background-color: #333;
border: none;
color: white;
padding: 10px 16px;
font-size: 24px;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.2s ease;
}
.controls button:hover {
background-color: #555;
}
/* Single-line lyrics container at the bottom (hidden by default). */
.lyrics {
position: absolute;
bottom: 100px; /* push it above the arrow */
width: 100%;
text-align: center;
font-size: 24px;
color: #bbbbbb;
opacity: 0;
transition: opacity 0.3s ease;
}
/* When .container is .show-lyrics, reveal the lyrics. */
.container.show-lyrics .lyrics {
opacity: 1;
}
/* The arrow button at the bottom center of the window. */
.arrow-button {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: none;
border: none;
font-size: 36px;
color: #ffffff;
cursor: pointer;
opacity: 0;
transition: opacity 0.3s ease;
}
/* Show the arrow button when hovering anywhere on body */
body:hover .arrow-button {
// opacity: 1;
opacity: 0;
}
</style>
</head>
<body>
<!-- Fixed minimize and close buttons in top-right -->
<button class="minimize-button" onclick="minimizeApp()"></button>
<button class="close-button" onclick="closeApp()">✕</button>
<div class="container" id="container">
<div class="card">
<div class="info">
<img class="album-art" id="albumArt" src="https://via.placeholder.com/150" alt="Album Art">
<div class="text-info">
<div class="title" id="songTitle">Loading...</div>
<div class="artist" id="songArtist"></div>
</div>
</div>
<div class="controls">
<button onclick="sendControl('previous')">⏮</button>
<button id="playPauseButton" onclick="sendControl('playpause')">⏯</button>
<button onclick="sendControl('next')">⏭</button>
</div>
</div>
<!-- Single line of lyrics that appears in the bottom half -->
<div class="lyrics" id="lyricsLine">
“Hello, is it me youre looking for?”
</div>
<!-- Arrow at the bottom -->
<button class="arrow-button" id="arrowButton" onclick="toggleLyrics()">▲</button>
</div>
<script>
const { ipcRenderer } = require('electron');
ipcRenderer.on('song-update', (event, data) => {
// Elements on the UI
const songTitleElem = document.getElementById('songTitle');
const songArtistElem = document.getElementById('songArtist');
const albumArtElem = document.getElementById('albumArt');
const playPauseButton = document.getElementById('playPauseButton');
if (data.paused) {
// Player is paused => show "Play" button
playPauseButton.textContent = "▶️";
} else {
// Player is playing => show "Pause" button and update track info
playPauseButton.textContent = "⏸️";
songTitleElem.innerText = data.title ?? "Unknown Title";
songArtistElem.innerText = data.artist ?? "Unknown Artist";
albumArtElem.src = data.albumArt ?? "https://via.placeholder.com/150";
}
});
// Sends commands (previous, playpause, next) to main process
function sendControl(command) {
ipcRenderer.send('media-control', command);
}
function closeApp() {
ipcRenderer.send('close-app');
}
function minimizeApp() {
ipcRenderer.send('minimize-app');
}
// Toggle lyrics arrow logic
function toggleLyrics() {
const container = document.getElementById('container');
const arrowBtn = document.getElementById('arrowButton');
container.classList.toggle('show-lyrics');
if (container.classList.contains('show-lyrics')) {
arrowBtn.textContent = '▼';
} else {
arrowBtn.textContent = '▲';
}
}
</script>
</body>
</html>
`;
}