Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Lyrics Feature #311

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,7 @@ package
*.orig

# generated version file
version.generated.ts
version.generated.ts

# idea generated folder
.idea/
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ Lofi is a mini Spotify player with visualizations. It is _not_ a replacement for
- Visualization-ready (WebGL)
- ≤ 100MB memory footprint

## Lyrics (new feature)

| Custom Font and background color | Minimalistic and simple|
|--|--|
|![](https://github.com/alient12/lofi/assets/73688480/2f0824c9-1a18-4730-9906-e9cf04030d14)|![](https://github.com/alient12/lofi/assets/73688480/0a95ac65-68b8-4a9d-84e5-ab3ad671024e)|

Installing `Circular Std Book` font is recommanded for lyrics.

# Building

To build, you'll need `node-gyp`, a compatible Python version (2.x), and your operating system's SDK (Microsoft Build Tools or Xcode).
Expand Down
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const MAX_BAR_THICKNESS = 20;
export const MIN_FONT_SIZE = 6;
export const MAX_FONT_SIZE = 32;
export const TRACK_INFO_GAP = { X: 10, Y: 10 };
export const LYRICS_GAP = { X: 0, Y: 10 };
export const MAX_CORNER_RADIUS = 20;

export const MIN_SKIP_SONG_DELAY = 5;
Expand All @@ -22,6 +23,7 @@ export enum WindowTitle {
FullscreenViz = 'fullscreen-visualization',
Settings = 'Lofi Settings',
TrackInfo = 'track-info',
Lyrics = 'lyrics',
}

export enum WindowName {
Expand All @@ -30,6 +32,7 @@ export enum WindowName {
FullscreenViz = 'fullscreen-visualization',
Settings = 'settings',
TrackInfo = 'track-info',
Lyrics = 'lyrics',
}

export enum IpcMessage {
Expand All @@ -53,4 +56,5 @@ export enum ApplicationUrl {
Help = 'https://www.lofi.rocks/help',
Discord = 'https://discord.gg/YuH9UJk',
GitHub = 'https://github.com/dvx/lofi',
FindLyricsToken = 'https://github.com/akashrchandran/syrics/wiki/Finding-sp_dc',
}
55 changes: 54 additions & 1 deletion src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
nativeImage,
Rectangle,
screen,
session,
shell,
Tray,
} from 'electron';
Expand All @@ -37,8 +38,10 @@ import {
getAboutWindowOptions,
getFullscreenVisualizationWindowOptions,
getFullscreenVizBounds,
getLyricsWindowOptions,
getSettingsWindowOptions,
getTrackInfoWindowOptions,
moveLyric,
moveTrackInfo,
setAlwaysOnTop,
settingsSchema,
Expand Down Expand Up @@ -142,6 +145,7 @@ const createMainWindow = (): void => {
// See: https://github.com/electron/electron/issues/9477#issuecomment-406833003
mainWindow.setBounds(bounds);
moveTrackInfo(mainWindow, screen);
moveLyric(mainWindow, screen);

mainWindow.webContents.send(IpcMessage.WindowMoved, bounds);
});
Expand All @@ -162,6 +166,7 @@ const createMainWindow = (): void => {

mainWindow.on('resize', () => {
moveTrackInfo(mainWindow, screen);
moveLyric(mainWindow, screen);
});

mainWindow.on('resized', () => {
Expand All @@ -174,7 +179,10 @@ const createMainWindow = (): void => {

ipcMain.on(
IpcMessage.SettingsChanged,
(_: Event, { x, y, size, isAlwaysOnTop, isDebug, isVisibleInTaskbar, visualizationScreenId }: Settings) => {
(
_: Event,
{ x, y, size, isAlwaysOnTop, isDebug, isVisibleInTaskbar, visualizationScreenId, SPDCToken }: Settings
) => {
setAlwaysOnTop({ window: mainWindow, isAlwaysOnTop });
mainWindow.setSkipTaskbar(!isVisibleInTaskbar);
showDevTool(mainWindow, isDebug);
Expand All @@ -184,12 +192,26 @@ const createMainWindow = (): void => {
mainWindow.center();
}
moveTrackInfo(mainWindow, screen);
moveLyric(mainWindow, screen);

const fullscreenVizWindow = findWindow(WindowTitle.FullscreenViz);
if (fullscreenVizWindow) {
const fullscreenVizBounds = getFullscreenVizBounds(mainWindow.getBounds(), screen, visualizationScreenId);
fullscreenVizWindow.setBounds(fullscreenVizBounds);
}
if (SPDCToken !== '') {
session.defaultSession.cookies.set({
url: 'https://spotify.com',
name: 'sp_dc',
value: SPDCToken,
sameSite: 'no_restriction',
domain: '.spotify.com',
secure: true,
httpOnly: true,
path: '/',
expirationDate: new Date().getTime() + 24 * 60 * 60 * 1000,
});
}
}
);

Expand Down Expand Up @@ -262,6 +284,13 @@ const createMainWindow = (): void => {
};
}

case WindowName.Lyrics: {
return {
action: 'allow',
overrideBrowserWindowOptions: getLyricsWindowOptions(mainWindow, settings.isAlwaysOnTop),
};
}

case WindowName.Auth: {
shell.openExternal(details.url);
break;
Expand Down Expand Up @@ -324,6 +353,16 @@ const createMainWindow = (): void => {
break;
}

case WindowName.Lyrics: {
moveLyric(mainWindow, screen);
childWindow.setIgnoreMouseEvents(true);
setAlwaysOnTop({ window: childWindow, isAlwaysOnTop: settings.isAlwaysOnTop });
if (MACOS) {
childWindow.setWindowButtonVisibility(false);
}
break;
}

default: {
break;
}
Expand All @@ -342,6 +381,19 @@ app.on('ready', () => {
}

createMainWindow();
if (settings.SPDCToken !== '') {
session.defaultSession.cookies.set({
url: 'https://spotify.com',
name: 'sp_dc',
value: settings.SPDCToken,
sameSite: 'no_restriction',
domain: '.spotify.com',
secure: true,
httpOnly: true,
path: '/',
expirationDate: new Date().getTime() + 24 * 60 * 60 * 1000,
});
}

tray = new Tray(icon);

Expand Down Expand Up @@ -397,6 +449,7 @@ app.on('ready', () => {
const isOnLeft = checkIfAppIsOnLeftSide(currentDisplay, bounds.x, bounds.width);
mainWindow.webContents.send(IpcMessage.WindowReady, { isOnLeft, displays });
moveTrackInfo(mainWindow, screen);
moveLyric(mainWindow, screen);
});
});

Expand Down
46 changes: 44 additions & 2 deletions src/main/main.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { z } from 'zod';

import {
IpcMessage,
LYRICS_GAP,
MAX_BAR_THICKNESS,
MAX_SIDE_LENGTH,
MAX_SKIP_SONG_DELAY,
Expand All @@ -29,8 +30,8 @@ export const getCommonWindowOptions = (): BrowserWindowConstructorOptions => ({

export const getSettingsWindowOptions = (): BrowserWindowConstructorOptions => ({
...getCommonWindowOptions(),
height: 420,
minHeight: 420,
height: 580,
minHeight: 580,
width: 420,
minWidth: 420,
title: WindowTitle.Settings,
Expand Down Expand Up @@ -74,6 +75,26 @@ export const getTrackInfoWindowOptions = (
};
};

export const getLyricsWindowOptions = (
mainWindow: BrowserWindow,
isAlwaysOnTop: boolean
): BrowserWindowConstructorOptions => {
const { x, y, width, height } = mainWindow.getBounds();
return {
...getCommonWindowOptions(),
parent: mainWindow,
skipTaskbar: true,
alwaysOnTop: isAlwaysOnTop,
height: 1000,
width: 1000,
transparent: true,
center: false,
x: x + LYRICS_GAP.X - width,
y: y + height + LYRICS_GAP.Y,
title: WindowTitle.Lyrics,
};
};

export const showDevTool = (window: BrowserWindow, isShow: boolean): void => {
if (isShow) {
window.webContents.openDevTools({ mode: 'detach' });
Expand Down Expand Up @@ -128,6 +149,27 @@ export const moveTrackInfo = (mainWindow: BrowserWindow, screen: Screen): void =
mainWindow.webContents.send(IpcMessage.SideChanged, { isOnLeft });
};

export const moveLyric = (mainWindow: BrowserWindow, screen: Screen): void => {
const { x, y, width, height } = mainWindow.getBounds();
const LyricsWindow = findWindow(WindowTitle.Lyrics);
if (!LyricsWindow) {
return;
}

const currentDisplay = screen.getDisplayNearestPoint({ x, y });
const isOnLeft = checkIfAppIsOnLeftSide(currentDisplay, x, width);

const originalBounds = LyricsWindow.getBounds();
const newBounds = {
...originalBounds,
x: isOnLeft ? x + LYRICS_GAP.X : x - originalBounds.width - LYRICS_GAP.X + width,
y: y + height + LYRICS_GAP.Y,
};

LyricsWindow.setBounds(newBounds);
mainWindow.webContents.send(IpcMessage.SideChanged, { isOnLeft });
};

export const settingsSchema = z.object({
x: z.number(),
y: z.number(),
Expand Down
26 changes: 26 additions & 0 deletions src/models/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ export interface Settings {
showFreemiumWarning: boolean;
cornerRadius: number;
trackInfoRefreshTimeInSeconds: number;
SPDCToken: string;
isShowLyrics: boolean;
isAlwaysShowLyrics: boolean;
lyricMaxLength: number;
lyricsFontSize: number;
lyricsColor: string;
nextLyricsColor: string;
lyricsBackgroundColor: string;
lyricsBackgroundOpacity: number;
lyricsFont: string;
isLyricsBlur: boolean;
isLyricsRandomBackground: boolean;
lyricsCornerRadius: number;
}

export const DEFAULT_SETTINGS: Settings = {
Expand Down Expand Up @@ -68,4 +81,17 @@ export const DEFAULT_SETTINGS: Settings = {
showFreemiumWarning: true,
cornerRadius: 0,
trackInfoRefreshTimeInSeconds: 1,
SPDCToken: '',
isShowLyrics: false,
isAlwaysShowLyrics: false,
lyricMaxLength: 30,
lyricsFontSize: 14,
lyricsColor: '#FFFFFF',
nextLyricsColor: '#000000',
lyricsBackgroundColor: '#000000',
lyricsBackgroundOpacity: 50,
lyricsFont: 'Inter UI',
isLyricsBlur: true,
isLyricsRandomBackground: true,
lyricsCornerRadius: 0,
};
Loading