added track downloading feature & new screenshot of the app window

This commit is contained in:
KRTirtho 2021-05-03 18:45:20 +06:00
parent 35da4d5fd4
commit e4ef120687
8 changed files with 9354 additions and 25 deletions

View File

@ -1,7 +1,7 @@
![Spotube](assets/spotube_banner.svg)
Spotube is a [qt](https://qt.io) based lightweight spotify client which uses [nodegui/react-nodegui](https://github.com/nodegui/react-nodegui) as frontend & nodejs as backend. It utilizes the power of Spotify & Youtube's public API & creates a hazardless, performant & resource friendly User Experience
![spotube](https://user-images.githubusercontent.com/61944859/111771249-a7d38180-88d5-11eb-85f2-d9db57717694.png)
![Application Screenshot](assets/spotube-screenshot.png)
## Features
@ -23,10 +23,10 @@ Don't worry **spotify premium isn't required**😱. But some extra packages are
- [MPV](https://mpv.io/installation/) player for playing the actual audio
- [youtube-dl](https://github.com/ytdl-org/youtube-dl) for streaming the audio from youtube. It already comes pre bundled with mpv
**Tip!:** If you're using **[Windows]()** try installing **mpv & youtube-dl** player with **[chocolatey](https://chocolatey.org/install) package manager** as it'd make the installation a lot easier.
> **Tip!:** If you're using **[Windows]()** try installing **mpv & youtube-dl** player with **[chocolatey](https://chocolatey.org/install) package manager** as it'd make the installation a lot easier.
**But always install youtube-dl first & then mpv player**
**Important for [Ubuntu/Debian]():** If you're using any **ubuntu/debian** based linux distro then **youtube-dl** installed from the typical **apt-get** repositories will most likely not work as that version is older than current release. So remove it & install from the repository manually
> **Important for [Ubuntu/Debian]():** If you're using any **ubuntu/debian** based linux distro then **youtube-dl** installed from the typical **apt-get** repositories will most likely not work as that version is older than current release. So remove it & install from the repository manually
Remove the **youtube-dl** installed with **mpv** player or from **apt package manger**
@ -39,10 +39,9 @@ Now, Install youtube-dl from
- official github repo: https://github.com/ytdl-org/youtube-dl#installation (recommended)
**or**
- snap installation
```bash
$ snap install youtube-dl
```
```bash
$ snap install youtube-dl
```
## Installation
@ -75,7 +74,7 @@ You need a spotify account & a web app for
- Click on **SHOW CLIENT SECRET** to reveal the **clientSecret**. Then copy the **clientID**, **clientSecret** & paste in the **Spotube's** respective fields
![step-4](https://user-images.githubusercontent.com/61944859/111769501-7fe31e80-88d3-11eb-8fc1-f3655dbd4711.png)
**[Important]!**: No personal data or any kind of sensitive information won't be collected from spotify. Don't believe? See the code for yourself
> **Note!**: No personal data or any kind of sensitive information won't be collected from spotify. Don't believe? See the code for yourself
### Building from source
@ -146,7 +145,7 @@ $ npm start
## Known Issues
There will be some glitches, lags & stuck motions because of the library Spotube is currently using under the hood. It has some issues with layouts thus sometime some contents aren't shown or overflows out of the window. But resizing the window would fix this issue. Soon there will be some updates fixing this sort of layout related problems
There will be some glitches, lags & stuck motions because of the library Spotube is currently using under the hood. It has some issues with layouts thus sometimes some contents aren't shown or overflows out of the window. But resizing the window would fix this issue. Soon there will be some updates fixing this sort of layout related problems
## TODO:
- [ ] Compile, Debug & Build for **MacOS**
@ -158,8 +157,7 @@ There will be some glitches, lags & stuck motions because of the library Spotube
## Things that don't work
- Shows & Podcasts aren't supported as it'd require premium anyway
- Beautiful UI (you missed it, see the title😂^)
- Images aren't added to ensure the lowest resource usage
- Beautiful UI (you missed it, see the title😂👆)
- OS Media Controls
#### Social handlers

View File

@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="download" class="svg-inline--fa fa-download fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="currentColor" d="M216 0h80c13.3 0 24 10.7 24 24v168h87.7c17.8 0 26.7 21.5 14.1 34.1L269.7 378.3c-7.5 7.5-19.8 7.5-27.3 0L90.1 226.1c-12.6-12.6-3.7-34.1 14.1-34.1H192V24c0-13.3 10.7-24 24-24zm296 376v112c0 13.3-10.7 24-24 24H24c-13.3 0-24-10.7-24-24V376c0-13.3 10.7-24 24-24h146.7l49 49c20.1 20.1 52.5 20.1 72.6 0l49-49H488c13.3 0 24 10.7 24 24zm-124 88c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20zm64 0c0-11-9-20-20-20s-20 9-20 20 9 20 20 20 20-9 20-20z"></path></svg>

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 KiB

9273
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -41,7 +41,8 @@
"react-router": "^5.2.0",
"scrape-yt": "^1.4.7",
"spotify-web-api-node": "^5.0.2",
"uuid": "^8.3.2"
"uuid": "^8.3.2",
"ytdl-core": "^4.5.0"
},
"devDependencies": {
"@babel/core": "^7.13.10",

View File

@ -6,12 +6,13 @@ import { shuffleArray } from "../helpers/shuffleArray";
import NodeMpv from "node-mpv";
import { getYoutubeTrack, YoutubeTrack } from "../helpers/getYoutubeTrack";
import PlayerProgressBar from "./PlayerProgressBar";
import { random as shuffleIcon, play, pause, backward, forward, stop, heartRegular, heart, musicNode } from "../icons";
import { random as shuffleIcon, play, pause, backward, forward, stop, heartRegular, heart, musicNode, download } from "../icons";
import IconButton from "./shared/IconButton";
import showError from "../helpers/showError";
import useTrackReaction from "../hooks/useTrackReaction";
import ManualLyricDialog from "./ManualLyricDialog";
import { LocalStorageKeys } from "../conf";
import useDownloadQueue from "../hooks/useDownloadQueue";
export const audioPlayer = new NodeMpv(
{
@ -27,7 +28,9 @@ export const audioPlayer = new NodeMpv(
function Player(): ReactElement {
const { currentTrack, currentPlaylist, setCurrentTrack, setCurrentPlaylist } = useContext(playerContext);
const { reactToTrack, isFavorite } = useTrackReaction();
const cachedVolume = localStorage.getItem(LocalStorageKeys.volume);
const [isPaused, setIsPaused] = useState(true);
const [volume, setVolume] = useState<number>(() => (cachedVolume ? parseFloat(cachedVolume) : 55));
const [totalDuration, setTotalDuration] = useState<number>(0);
@ -36,6 +39,8 @@ function Player(): ReactElement {
const [isStopped, setIsStopped] = useState<boolean>(false);
const [openLyrics, setOpenLyrics] = useState<boolean>(false);
const [currentYtTrack, setCurrentYtTrack] = useState<YoutubeTrack>();
const { addToQueue, isActiveDownloading, isFinishedDownloading } = useDownloadQueue();
const playlistTracksIds = currentPlaylist?.tracks.map((t) => t.track.id);
const volumeHandler = useEventHandler<QAbstractSliderSignals>(
{
@ -230,6 +235,16 @@ function Player(): ReactElement {
</GridColumn>
<GridColumn width={2}>
<BoxView>
<IconButton
style={isActiveDownloading() && !isFinishedDownloading() ? "background-color: green;" : ""}
enabled={!!currentYtTrack}
icon={new QIcon(download)}
on={{
clicked() {
currentYtTrack && addToQueue(currentYtTrack);
},
}}
/>
<IconButton
on={{
clicked() {

View File

@ -0,0 +1,59 @@
import { useContext, useEffect, useState } from "react";
import ytdl from "ytdl-core";
import fs from "fs";
import { YoutubeTrack } from "../helpers/getYoutubeTrack";
import { join } from "path";
import os from "os";
import playerContext from "../context/playerContext";
import showError from "../helpers/showError";
function useDownloadQueue() {
const [downloadQueue, setDownloadQueue] = useState<YoutubeTrack[]>([]);
const [completedQueue, setCompletedQueue] = useState<YoutubeTrack[]>([]);
const { currentTrack } = useContext(playerContext);
function addToQueue(obj: YoutubeTrack) {
setDownloadQueue([...downloadQueue, obj]);
}
const completedTrackIds = completedQueue.map((x) => x.id);
const downloadingTrackIds = downloadQueue.map((x) => x.id);
function isActiveDownloading() {
return downloadingTrackIds.includes(currentTrack?.id ?? "");
}
function isFinishedDownloading() {
return completedTrackIds.includes(currentTrack?.id ?? "");
}
useEffect(() => {
downloadQueue.forEach(async (el) => {
if (!completedTrackIds.includes(el.id)) {
ytdl(el.youtube_uri, {
filter: "audioonly",
})
.pipe(
fs.createWriteStream(
join(
os.homedir(),
"Music",
`${el.name} - ${el.artists
.map((x) => x.name)
.join(", ")
.trim()}.mp3`
)
)
)
.on("error", (err) => {
showError(err, `[failed to download ${el.name}]: `);
})
.on("finish", () => {
setCompletedQueue([...completedQueue, el]);
});
}
});
}, [downloadQueue]);
return { addToQueue, isFinishedDownloading, isActiveDownloading };
}
export default useDownloadQueue;

View File

@ -12,6 +12,7 @@ import _loadingSpinner from "../assets/loading-spinner.gif";
import _settingsCog from "../assets/setting-cog.svg"
import _times from "../assets/times-solid.svg"
import _musicNode from "../assets/music-solid.svg"
import _download from "../assets/download-solid.svg"
export const play = _play;
export const pause = _pause;
@ -27,3 +28,4 @@ export const loadingSpinner = _loadingSpinner;
export const settingsCog = _settingsCog;
export const times = _times;
export const musicNode = _musicNode;
export const download = _download;