Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
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
6 changes: 2 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ jobs:
node-version: 18
check-latest: true

- name: Print environment variables
run: node -e "console.log(process.env)"

- name: Build/release Electron app
uses: samuelmeuli/action-electron-builder@v1
with:
Expand All @@ -39,5 +36,6 @@ jobs:

# If the commit is tagged with a version (e.g. "v1.0.0"),
# release the app after building
release: true
# release: ${{ startsWith(github.ref, 'refs/heads/master') }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}
# release: ${{ startsWith(github.ref, 'refs/tags/v') }}
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Jest Tests

on: [push, pull_request]
on: [push]

jobs:
build:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<img alt="GitHub package.json version" src="https://img.shields.io/github/package-json/v/Sandakan/Nora?color=blue&label=latest%20version&style=for-the-badge">
<a href="https://github.com/Sandakan/Nora/blob/master/LICENSE"><img alt="GitHub license" src="https://img.shields.io/github/license/Sandakan/Nora?style=for-the-badge"></a>
<a href="https://github.com/Sandakan/Nora/issues"><img alt="GitHub issues" src="https://img.shields.io/github/issues/Sandakan/Oto-Music-for-Desktop?style=for-the-badge"></a>
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/Sandakan/Nora/build.yml?branch=master&style=for-the-badge">
</div>

<br/>
Expand Down
Binary file modified assets/other/artwork 0.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/other/artwork 1.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/other/artwork 2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/other/artwork 3.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/other/artwork 5.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/other/artwork 6.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 6 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,49 +216,37 @@
"fileAssociations": [
{
"mimeType": "audio/mpeg",
"ext": [
"mp3"
],
"ext": "mp3",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/mp3.ico"
},
{
"mimeType": "audio/wav",
"ext": [
"wav"
],
"ext": "wav",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/wav.ico"
},
{
"mimeType": "audio/ogg",
"ext": [
"ogg"
],
"ext": "ogg",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/ogg.ico"
},
{
"mimeType": "audio/aac",
"ext": [
"aac"
],
"ext": "aac",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/aac.ico"
},
{
"mimeType": "audio/x-m4r",
"ext": [
"m4r"
],
"ext": "m4r",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/m4r.ico"
},
{
"mimeType": "audio/flac",
"ext": [
"flac"
],
"ext": "flac",
"role": "Editor",
"icon": "./assets/installer_assets/file_associated_icons/flac.ico"
}
Expand Down
8 changes: 6 additions & 2 deletions src/renderer/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import {
AppUpdateContextType,
} from './contexts/AppUpdateContext';
import { SongPositionContext } from './contexts/SongPositionContext';
import packageFile from '../../package.json';

import useNetworkConnectivity from './hooks/useNetworkConnectivity';

import TitleBar from './components/TitleBar/TitleBar';
import SongControlsContainer from './components/SongsControlsContainer/SongControlsContainer';
import BodyAndSideBarContainer from './components/BodyAndSidebarContainer';
Expand All @@ -21,13 +23,15 @@ import Button from './components/Button';
import ReleaseNotesPrompt from './components/ReleaseNotesPrompt/ReleaseNotesPrompt';
import Img from './components/Img';
import Preloader from './components/Preloader/Preloader';

import isLatestVersion from './utils/isLatestVersion';
import roundTo from './utils/roundTo';
import storage, { LOCAL_STORAGE_DEFAULT_TEMPLATE } from './utils/localStorage';
import useNetworkConnectivity from './hooks/useNetworkConnectivity';
import { isDataChanged } from './utils/hasDataChanged';
import log from './utils/log';

import packageFile from '../../package.json';

interface AppReducer {
userData: UserData;
isDarkMode: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/AlbumInfoPage/AlbumInfoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ const AlbumInfoPage = () => {

const albumArtistComponents = React.useMemo(() => {
const { artists } = albumContent.albumData;
if (artists)
if (Array.isArray(artists) && artists.length > 0)
return artists
.map((artist, i) => {
const arr = [
Expand All @@ -248,7 +248,7 @@ const AlbumInfoPage = () => {
return arr;
})
.flat();
return <span>Unknown Artist</span>;
return <span className="text-xs font-normal">Unknown Artist</span>;
}, [albumContent.albumData]);

const calculateTotalTime = React.useCallback(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/AlbumsPage/Album.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ export const Album = (props: AlbumProp) => {

const albumArtists = React.useMemo(() => {
const { artists } = props;
if (Array.isArray(artists)) {
if (Array.isArray(artists) && artists.length > 0) {
return artists
.map((artist, i) => {
const arr = [
Expand Down Expand Up @@ -200,7 +200,7 @@ export const Album = (props: AlbumProp) => {
})
.flat();
}
return <span>Unknown Artist</span>;
return <span className="text-xs font-normal">Unknown Artist</span>;
}, [isAMultipleSelection, props]);

const contextMenuItems = React.useMemo(() => {
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/components/ArtistInfoPage/ArtistInfoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ const ArtistInfoPage = () => {
return (
<Album
index={index}
key={`${album.albumId}-${album.title}`}
key={album.albumId}
albumId={album.albumId}
artists={album.artists}
artworkPaths={album.artworkPaths}
Expand Down
37 changes: 23 additions & 14 deletions src/renderer/components/Body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,31 @@ const Body = React.memo(() => {
React.useEffect(() => {
if (typeof currentlyActivePage.data?.scrollToId === 'string') {
const { scrollToId } = currentlyActivePage.data;
const element = document.querySelector(scrollToId as string);
let retryCount = 0;

if (element && bodyRef.current?.contains(element))
setTimeout(
() =>
element.scrollIntoView({
behavior: 'smooth',
block: 'center',
}),
250
);
else
console.warn(
`Element with id ${scrollToId} didn't exist to scroll into view.`
);
const timeoutId = setInterval(() => {
const element = document.querySelector(scrollToId as string);

if (retryCount >= 3) {
clearInterval(timeoutId);
return console.warn(
`Element with id ${scrollToId} didn't exist to scroll into view.`
);
}
if (element && bodyRef.current?.contains(element)) {
clearInterval(timeoutId);
return element.scrollIntoView({
behavior: 'smooth',
block: 'center',
});
}
retryCount += 1;
return undefined;
}, 250);

return () => clearInterval(timeoutId);
}
return undefined;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentlyActivePage.data?.scrollToId]);

Expand Down
23 changes: 17 additions & 6 deletions src/renderer/components/NotificationPanel/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ const Notification = (props: AppNotification) => {
}%`;

const removeNotification = React.useCallback(() => {
const isNotificationAnimationDisabled =
localStorageData?.preferences?.isReducedMotion ||
type === 'WITH_PROGRESS_BAR';

if (notificationTimeoutIdRef.current)
clearTimeout(notificationTimeoutIdRef.current);
if (
notificationRef.current &&
!localStorageData?.preferences?.isReducedMotion
) {

if (notificationRef.current && !isNotificationAnimationDisabled) {
notificationRef.current.classList.add('disappear-to-bottom');
notificationRef.current.addEventListener('animationend', () =>
updateNotifications((currNotifications) =>
Expand All @@ -45,7 +47,12 @@ const Notification = (props: AppNotification) => {
updateNotifications((currNotifications) =>
currNotifications.filter((x) => x.id !== id)
);
}, [id, localStorageData?.preferences?.isReducedMotion, updateNotifications]);
}, [
id,
localStorageData?.preferences?.isReducedMotion,
type,
updateNotifications,
]);

React.useLayoutEffect(() => {
const notification = notificationRef.current;
Expand All @@ -72,7 +79,11 @@ const Notification = (props: AppNotification) => {
}, [delay, id, removeNotification, updateNotifications]);
return (
<div
className="notification appear-from-bottom group mt-4 flex h-fit max-h-32 min-h-[50px] w-fit min-w-[300px] max-w-sm justify-between rounded-2xl bg-context-menu-background py-2 text-sm font-light text-font-color-black shadow-[5px_25px_50px_0px_rgba(0,0,0,0.2)] backdrop-blur-sm transition-[opacity,transform,visibility] ease-in-out dark:bg-dark-context-menu-background dark:text-font-color-white"
className={`notification ${
type !== 'WITH_PROGRESS_BAR' && 'appear-from-bottom'
} group mt-4 flex h-fit max-h-32 min-h-[50px] w-fit min-w-[300px] max-w-sm justify-between rounded-2xl bg-context-menu-background py-2 text-sm font-light text-font-color-black shadow-[5px_25px_50px_0px_rgba(0,0,0,0.2)] backdrop-blur-sm transition-[opacity,transform,visibility] ease-in-out dark:bg-dark-context-menu-background dark:text-font-color-white ${
progressBarData && 'duration-0'
}`}
id="notificationPanelsContainer"
ref={notificationRef}
style={notificationPanelStyles}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@ const MusixmatchSettingsPrompt = () => {
tooltipLabel={showToken ? 'Hide Token' : 'Show Token'}
className="!m-0 !border-0 !p-0"
clickHandler={() => setShowToken((prevState) => !prevState)}
isDisabled={
token === '' ||
inputRef.current?.value === userData?.customMusixmatchUserToken
}
isDisabled={token === '' || !!userData?.customMusixmatchUserToken}
/>
<Button
label="Update Token"
className="ml-4"
isDisabled={!isAValidToken || successState === 'success'}
isDisabled={
!isAValidToken ||
successState === 'success' ||
inputRef.current?.value === userData?.customMusixmatchUserToken
}
clickHandler={(_e, setIsDisabled, setIsPending) => {
if (isAValidToken) {
setIsDisabled(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const AudioPlaybackSettings = () => {
/>
</li>

<li className="playback-rate mb-6">
<li className="playback-rate mb-6" id="playbackRateInterval">
<div className="description">
Change the default playback rate of the player.
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/SongInfoPage/SongInfoPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ const SongInfoPage = () => {
}, [fetchSongInfo]);
const songArtists = React.useMemo(() => {
const artists = songInfo?.artists;
if (Array.isArray(artists)) {
if (Array.isArray(artists) && artists.length > 0) {
return artists
.map((artist, i, artistArr) => {
const arr = [
Expand Down Expand Up @@ -145,7 +145,7 @@ const SongInfoPage = () => {
})
.flat();
}
return <span>Unknown Artist</span>;
return <span className="text-xs font-normal">Unknown Artist</span>;
}, [bodyBackgroundImage, songInfo?.artists]);

const { allTimeListens, thisYearListens, thisMonthListens } =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ const SongsWithFeaturingArtistsSuggestion = (props: Props) => {
</p>
<Checkbox
id="featArtistsTitleReset"
labelContent="Remove information related to featuring artists in the song title"
labelContent="Remove featuring artists information from song title after adding artists to the song."
className="my-4 !text-sm"
isChecked={isRemovingFeatInfoFromTitle}
checkedStateUpdateFunction={(state) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,20 +124,22 @@ const CurrentlyPlayingSongInfoContainer = () => {
);

const songArtists = React.useMemo(() => {
if (currentSongData.songId && Array.isArray(currentSongData.artists)) {
if (currentSongData.artists.length > 0) {
return currentSongData.artists
const { songId, artists, isKnownSource } = currentSongData;

if (songId && Array.isArray(artists)) {
if (artists.length > 0) {
return artists
.map((artist, i, artistArr) => {
const arr = [
<SongArtist
key={artist.artistId}
artistId={artist.artistId}
name={artist.name}
isFromKnownSource={currentSongData.isKnownSource}
isFromKnownSource={isKnownSource}
/>,
];

if ((currentSongData.artists?.length ?? 1) - 1 !== i)
if ((artists.length ?? 1) - 1 !== i)
arr.push(
<span
key={`${artistArr[i].name},${artistArr[i + 1].name}`}
Expand All @@ -151,14 +153,10 @@ const CurrentlyPlayingSongInfoContainer = () => {
})
.flat();
}
return <span>Unknown Artist</span>;
return <span className="text-xs font-normal">Unknown Artist</span>;
}
return '';
}, [
currentSongData.artists,
currentSongData.songId,
currentSongData.isKnownSource,
]);
}, [currentSongData]);

const contextMenuCurrentSongData =
React.useMemo((): ContextMenuAdditionalData => {
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/components/SongsPage/Song.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const Song = React.forwardRef(
}, [multipleSelectionsData, songId]);

const songArtists = React.useMemo(() => {
if (Array.isArray(artists)) {
if (Array.isArray(artists) && artists.length > 0) {
return artists
.map((artist, i) => {
const arr = [
Expand All @@ -175,7 +175,7 @@ const Song = React.forwardRef(
})
.flat();
}
return <span>Unknown Artist</span>;
return <span className="text-xs font-normal">Unknown Artist</span>;
}, [artists, currentSongData.songId, isAMultipleSelection, songId]);

const goToSongInfoPage = React.useCallback(() => {
Expand Down
Loading