Skip to content

Commit 9f66899

Browse files
Merge pull request #19 from andrewmcgivery/beta
Version 1.2.0
2 parents 98316ae + 9a5bdb0 commit 9f66899

28 files changed

+3035
-465
lines changed

README.md

+12
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,18 @@ Additionally, when listening to a custom soundscape, you can use the new "next"
2626
![Screenshot of editing a custom soundscape](screenshot4.png)
2727
![Screenshot of soundscapes player while playing a custom soundscape](screenshot5.png)
2828

29+
### My Music - Local Music Library
30+
31+
The "My Music" soundscape allows you to have a full music player experience right within Obsidian using your local MP3 music files. Upon selecting your local music folder, the plugin will index your music and occasionally re-index it in the background.
32+
33+
My Music supports playing with the mini-player in the status bar as well as a new dedicated My Music view with a new icon on the Ribbon sidebar once the "My Music" soundscape is selected. You can close this view and the music will continue playing.
34+
35+
Within the My Music view, you can play, pause, next, previous, seek, shuffle, and search.
36+
37+
![Settings view with My Music selected](screenshot6.png)
38+
39+
![My Music view within Obsidian](screenshot7.png)
40+
2941
## Requesting New Soundscapes
3042

3143
Have an idea for a new Soundscape? [Open an issue](https://github.com/andrewmcgivery/obsidian-soundscapes/issues/new) and link a Youtube video and why we should add it!

React/Components/App/App.scss

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
.soundscapesmymusic {
2+
.view-header {
3+
display: none;
4+
}
5+
6+
.view-content {
7+
padding: 0;
8+
}
9+
10+
.soundscapesmymusic-musiclist {
11+
overflow: scroll;
12+
position: absolute;
13+
top: 60px;
14+
left: 0;
15+
right: 0;
16+
bottom: 0;
17+
z-index: 400;
18+
padding-bottom: 40px;
19+
20+
.soundscapesmymusic-musiclist-table {
21+
border-collapse: collapse;
22+
width: 100%;
23+
24+
thead {
25+
tr {
26+
text-align: left;
27+
background-color: var(--background-secondary);
28+
position: sticky;
29+
top: 0;
30+
z-index: 400;
31+
32+
th {
33+
padding: 8px 12px;
34+
font-size: 0.7em;
35+
}
36+
}
37+
}
38+
39+
tbody {
40+
tr {
41+
&:nth-child(odd) {
42+
background-color: var(--background-primary);
43+
}
44+
45+
&:nth-child(even) {
46+
background-color: var(--background-primary-alt);
47+
}
48+
49+
td {
50+
padding: 6px 12px;
51+
font-size: 1em;
52+
cursor: pointer;
53+
vertical-align: middle;
54+
line-height: 1;
55+
56+
&:first-child {
57+
width: 0;
58+
padding-right: 0;
59+
}
60+
61+
.lucide-icon {
62+
display: block;
63+
line-height: 0;
64+
color: var(--text-accent);
65+
66+
svg {
67+
height: 15px;
68+
}
69+
}
70+
}
71+
72+
&:hover {
73+
background-color: var(--background-modifier-hover);
74+
}
75+
}
76+
}
77+
}
78+
}
79+
}

React/Components/App/App.tsx

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import React, { useEffect, useState } from "react";
2+
import { useObsidianPluginContext } from "../../Context/ObsidianPluginContext";
3+
import Icon from "../Icon/Icon";
4+
import Header from "../Header/Header";
5+
import secondsToMinutesAndSeconds from "../../Utils/secondsToMinutesAndSeconds";
6+
import { LocalPlayerState } from "src/Types/Interfaces";
7+
import { PLAYER_STATE } from "src/Types/Enums";
8+
import { SoundscapesPluginSettings } from "src/Settings/Settings";
9+
10+
const App = () => {
11+
const { settingsObservable, localPlayerStateObservable, plugin } =
12+
useObsidianPluginContext();
13+
const [settings, setSettings] = useState<SoundscapesPluginSettings>(
14+
settingsObservable?.getValue()
15+
);
16+
const [localPlayerState, setLocalPlayerState] = useState<LocalPlayerState>(
17+
localPlayerStateObservable?.getValue()
18+
);
19+
20+
/**
21+
* Subscribe to settings from Obsidian
22+
*/
23+
useEffect(() => {
24+
const unsubscribe = settingsObservable?.onChange(
25+
(newSettings: SoundscapesPluginSettings) => {
26+
setSettings(newSettings);
27+
}
28+
);
29+
30+
return () => {
31+
unsubscribe?.();
32+
};
33+
}, [setSettings]);
34+
35+
/**
36+
* Subscribe to local player state from Obsidian
37+
*/
38+
useEffect(() => {
39+
const unsubscribe = localPlayerStateObservable?.onChange(
40+
(newState: LocalPlayerState) => {
41+
setLocalPlayerState(newState);
42+
}
43+
);
44+
45+
return () => {
46+
unsubscribe?.();
47+
};
48+
}, [setLocalPlayerState]);
49+
50+
return (
51+
<>
52+
<Header />
53+
<div className="soundscapesmymusic-musiclist">
54+
<table className="soundscapesmymusic-musiclist-table">
55+
<thead>
56+
<tr>
57+
<th></th>
58+
<th>Title</th>
59+
<th>Artist</th>
60+
<th>Album</th>
61+
<th>Time</th>
62+
</tr>
63+
</thead>
64+
<tbody>
65+
{settings.myMusicIndex.map((song) => (
66+
<tr
67+
key={song.fullPath}
68+
onDoubleClick={() =>
69+
plugin?.changeMyMusicTrack(song.fileName)
70+
}
71+
>
72+
<td>
73+
{localPlayerState.currentTrack?.fileName ===
74+
song.fileName &&
75+
localPlayerState.playerState ===
76+
PLAYER_STATE.PLAYING && (
77+
<Icon name="volume-2" />
78+
)}
79+
80+
{localPlayerState.currentTrack?.fileName ===
81+
song.fileName &&
82+
localPlayerState.playerState ===
83+
PLAYER_STATE.PAUSED && (
84+
<Icon name="volume" />
85+
)}
86+
</td>
87+
<td>{song.title}</td>
88+
<td>{song.artist}</td>
89+
<td>{song.album}</td>
90+
<td>
91+
{secondsToMinutesAndSeconds(
92+
song.duration || 0
93+
)}
94+
</td>
95+
</tr>
96+
))}
97+
</tbody>
98+
</table>
99+
</div>
100+
</>
101+
);
102+
};
103+
104+
export default App;

React/Components/Header/Header.scss

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
.soundscapesmymusic {
2+
.soundscapesmymusic-header {
3+
background-color: var(--background-primary);
4+
display: flex;
5+
align-items: center;
6+
padding: 0 42px;
7+
height: 60px;
8+
position: absolute;
9+
top: 0;
10+
left: 0;
11+
right: 0;
12+
gap: 1%;
13+
14+
.soundscapesmymusic-left {
15+
flex: 1;
16+
display: flex;
17+
align-items: center;
18+
19+
.soundscapesmymusic-left-controls {
20+
display: flex;
21+
align-items: center;
22+
gap: 12px;
23+
24+
.soundscapesmymusic-left-controls-button {
25+
color: var(--text-muted);
26+
background-color: transparent;
27+
border: none;
28+
box-shadow: none;
29+
cursor: pointer;
30+
padding: 0;
31+
display: block;
32+
line-height: 1;
33+
--icon-size: 1.5em;
34+
35+
&:hover {
36+
color: var(--text-normal);
37+
}
38+
39+
&.soundscapesmymusic-left-controls-button--large {
40+
--icon-size: 2em;
41+
}
42+
}
43+
}
44+
}
45+
46+
.soundscapesmymusic-volume {
47+
flex: 1;
48+
align-items: left;
49+
}
50+
51+
.soundscapesmymusic-middle {
52+
flex: 3;
53+
height: 100%;
54+
border-left: 1px solid var(--background-modifier-border);
55+
border-right: 1px solid var(--background-modifier-border);
56+
background-color: var(--background-primary-alt);
57+
display: flex;
58+
flex-direction: column;
59+
height: 100%;
60+
justify-content: space-between;
61+
overflow: hidden;
62+
min-width: 250px;
63+
64+
.soundscapesmymusic-middle-line1 {
65+
display: flex;
66+
align-items: center;
67+
justify-content: space-between;
68+
font-size: 1em;
69+
padding: 8px 8px 0 8px;
70+
71+
.soundscapesmymusic-middle-line1-button {
72+
color: var(--text-muted);
73+
background-color: transparent;
74+
border: none;
75+
box-shadow: none;
76+
cursor: pointer;
77+
padding: 0;
78+
display: block;
79+
line-height: 1;
80+
--icon-size: 1em;
81+
height: auto;
82+
83+
&:hover {
84+
color: var(--text-normal);
85+
}
86+
87+
&.soundscapesmymusic-middle-line1-button--active {
88+
color: var(--text-accent);
89+
}
90+
}
91+
92+
.soundscapesmymusic-middle-line1-left {
93+
width: 30px;
94+
}
95+
96+
.soundscapesmymusic-middle-line1-title {
97+
flex: 1;
98+
text-align: center;
99+
white-space: nowrap;
100+
overflow: hidden;
101+
position: relative;
102+
103+
&.soundscapesmymusic-middle-line1-title--scroll {
104+
.soundscapesmymusic-middle-line1-title-text {
105+
display: inline-block;
106+
animation: marquee 10s linear infinite;
107+
}
108+
}
109+
}
110+
111+
.soundscapesmymusic-middle-line1-right {
112+
width: 30px;
113+
text-align: right;
114+
}
115+
}
116+
117+
.soundscapesmymusic-middle-line2 {
118+
display: flex;
119+
align-items: center;
120+
justify-content: space-between;
121+
font-size: 0.8em;
122+
color: var(--text-muted);
123+
padding: 0 8px;
124+
125+
.soundscapesmymusic-middle-line2-left {
126+
width: 60px;
127+
}
128+
129+
.soundscapesmymusic-middle-line2-artist {
130+
flex: 1;
131+
text-align: center;
132+
white-space: nowrap;
133+
overflow: hidden;
134+
}
135+
136+
.soundscapesmymusic-middle-line2-right {
137+
width: 60px;
138+
text-align: right;
139+
}
140+
}
141+
142+
.soundscapesmymusic-middle-seekbar {
143+
width: 100%;
144+
margin: 0;
145+
146+
&::-webkit-slider-thumb {
147+
border-radius: 8px;
148+
width: 8px;
149+
}
150+
}
151+
}
152+
153+
.soundscapesmymusic-right {
154+
flex: 2;
155+
display: flex;
156+
justify-content: end;
157+
}
158+
}
159+
}

0 commit comments

Comments
 (0)