Partial Progress with rewriting parts of Song.js
Also started work on Writing Storage.js Storage.js manages info across sessions of melodii
This commit is contained in:
parent
dd58f5512f
commit
152ef58e41
11
src/App.js
11
src/App.js
|
@ -24,17 +24,16 @@ const filepath = new Filepath("C:\\Users\\Paoda\\Downloads\\Music");
|
||||||
(async () => {
|
(async () => {
|
||||||
let list = await filepath.getValidFiles();
|
let list = await filepath.getValidFiles();
|
||||||
|
|
||||||
let song = new Song(list[~~(Math.random() * list.length)]);
|
let song = new Song(list[~~(Math.random() * list.length)], true);
|
||||||
song = await Song.getMetadata(song);
|
await song.getMetadata();
|
||||||
Song.setAlbumArt(song.metadata);
|
|
||||||
|
|
||||||
mp.loadSong(song);
|
mp.loadSong(song);
|
||||||
// mp.play();
|
// mp.play();
|
||||||
|
|
||||||
mp.element.onended = async () => {
|
mp.element.onended = async () => {
|
||||||
let song = new Song(list[~~(Math.random() * list.length)]);
|
let song = new Song(list[~~(Math.random() * list.length)], true);
|
||||||
song = await Song.getMetadata(song);
|
await song.getMetadata();
|
||||||
Song.setAlbumArt(song.metadata);
|
|
||||||
mp.loadSong(song);
|
mp.loadSong(song);
|
||||||
mp.play();
|
mp.play();
|
||||||
};
|
};
|
||||||
|
|
|
@ -152,7 +152,7 @@ export default class Body extends React.Component {
|
||||||
term = parseInt(term, 10);
|
term = parseInt(term, 10);
|
||||||
temp.tbody = table.tbody.filter(obj => obj.year === term);
|
temp.tbody = table.tbody.filter(obj => obj.year === term);
|
||||||
} else {
|
} else {
|
||||||
// type == time
|
// type === time
|
||||||
term = term.toLowerCase();
|
term = term.toLowerCase();
|
||||||
temp.tbody = table.tbody.filter(obj =>
|
temp.tbody = table.tbody.filter(obj =>
|
||||||
obj.time.toLowerCase().includes(term)
|
obj.time.toLowerCase().includes(term)
|
||||||
|
|
|
@ -262,7 +262,7 @@ export function sortTable(table, term) {
|
||||||
return a.year - b.year;
|
return a.year - b.year;
|
||||||
});
|
});
|
||||||
} else if (term === "time") {
|
} else if (term === "time") {
|
||||||
//term == time convert the time into seconds
|
//term === time convert the time into seconds
|
||||||
//The messy else if + else is becomes a.inSeconds || b.inSeconds can be undefined.
|
//The messy else if + else is becomes a.inSeconds || b.inSeconds can be undefined.
|
||||||
tbody.sort((a, b) => {
|
tbody.sort((a, b) => {
|
||||||
if (a.inSeconds && b.inSeconds) {
|
if (a.inSeconds && b.inSeconds) {
|
||||||
|
|
|
@ -49,6 +49,8 @@ export default class MusicPlayer {
|
||||||
*/
|
*/
|
||||||
load(playlist) {
|
load(playlist) {
|
||||||
const song = playlist.next();
|
const song = playlist.next();
|
||||||
|
|
||||||
|
song.getMetadata().then(() => {
|
||||||
let path = song.location;
|
let path = song.location;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -58,12 +60,16 @@ export default class MusicPlayer {
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(path + " failed to load " + e.name + " from " + playlist.title);
|
console.error(path + " failed to load " + e.name + " from " + playlist.title);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads Song
|
/** Loads Song
|
||||||
* @param {Song} song
|
* @param {Song} song
|
||||||
*/
|
*/
|
||||||
loadSong(song) {
|
loadSong(song) {
|
||||||
|
|
||||||
|
song.displayAlbumArt();
|
||||||
|
|
||||||
if (archive.getCurrentSong() !== undefined)
|
if (archive.getCurrentSong() !== undefined)
|
||||||
archive.add(archive.getCurrentSong());
|
archive.add(archive.getCurrentSong());
|
||||||
let path = song.location;
|
let path = song.location;
|
||||||
|
|
|
@ -9,10 +9,85 @@ export default class Song {
|
||||||
* @param {String} path
|
* @param {String} path
|
||||||
* @param {Boolean} ShouldAlbumArtExist
|
* @param {Boolean} ShouldAlbumArtExist
|
||||||
*/
|
*/
|
||||||
constructor(path, ShouldAlbumArtExist) { //whether album art should exist
|
constructor(path, shouldCreateAlbumArt = false) { //whether album art should exist
|
||||||
this.location = path;
|
this.location = path;
|
||||||
|
this.title = "";
|
||||||
|
this.unf_time = 0;
|
||||||
|
this.album = "";
|
||||||
|
this.year = 0;
|
||||||
|
this.genres = [];
|
||||||
|
this.genre = "";
|
||||||
|
|
||||||
|
this.albumArt = "";
|
||||||
|
this.albumArtPresent = false;
|
||||||
|
|
||||||
|
this.shouldCreateAlbumArt = shouldCreateAlbumArt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Metadata from File.
|
||||||
|
*/
|
||||||
|
getMetadata() {
|
||||||
|
return new Promise((res, rej) => {
|
||||||
|
mm.parseFile(this.location, { native: true, duration: true }).then((metadata) => {
|
||||||
|
|
||||||
|
this.metadata = metadata;
|
||||||
|
|
||||||
|
console.log(metadata);
|
||||||
|
|
||||||
|
const format = metadata.format;
|
||||||
|
const common = metadata.common;
|
||||||
|
|
||||||
|
|
||||||
|
this.title = common.title || "";
|
||||||
|
this.unf_time = format.duration || 0;
|
||||||
|
this.album = common.album || "";
|
||||||
|
this.year = common.year || 0;
|
||||||
|
this.genre = common.genre ? common.genre.toString() : "";
|
||||||
|
|
||||||
|
if (this.shouldCreateAlbumArt) this.getAlbumArt(common.picture);
|
||||||
|
|
||||||
|
|
||||||
|
res();
|
||||||
|
}).catch((err) => rej(err));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and Loads Album Art. Saves it to Song instance.
|
||||||
|
* TODO: Move the Event emission to only occur when the song is played.
|
||||||
|
* @param {*} picture
|
||||||
|
*/
|
||||||
|
getAlbumArt(picture) {
|
||||||
|
if (picture) {
|
||||||
|
if (picture.length > 0) {
|
||||||
|
console.log(picture);
|
||||||
|
const pic = picture[0];
|
||||||
|
|
||||||
|
this.albumArt = URL.createObjectURL(new Blob([pic.data], {
|
||||||
|
'type': pic.format
|
||||||
|
}));
|
||||||
|
this.albumArtPresent = true;
|
||||||
|
} else console.error(this.title + ' Has Album Art, however, no data was found.');
|
||||||
|
|
||||||
|
} else console.warn(this.title, + ' does not have Album Art.');
|
||||||
|
}
|
||||||
|
|
||||||
|
displayAlbumArt() {
|
||||||
|
console.log("Album Art", this.albumArt);
|
||||||
|
console.log("Album Art is Present: ", this.albumArtPresent)
|
||||||
|
if (this.albumArtPresent) Emitter.emit('updateAlbumArt', this.albumart);
|
||||||
|
else Emitter.emit('updateAlbumArt', noalbumart);
|
||||||
|
}
|
||||||
|
|
||||||
|
get time() {
|
||||||
|
let min = ~~((format.duration % 3600) / 60);
|
||||||
|
let sec = ~~(format.duration % 60);
|
||||||
|
if (sec < 10) sec = "0" + sec;
|
||||||
|
return min + ":" + sec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets Metadata from Song
|
* Gets Metadata from Song
|
||||||
* @param {Song} song
|
* @param {Song} song
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
import Song from './Song';
|
||||||
|
import Filepath from './Filepath'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This classs Manages:
|
||||||
|
* - User Settings
|
||||||
|
* - Metadata Saving
|
||||||
|
* - Passing of Metadata to Table Generation
|
||||||
|
*
|
||||||
|
* The Goal of This function is to remove the complete dependence of electron-settings
|
||||||
|
* and the fact that melodii (2019.03.22) relies on Tabe.js for Saving metadata as well as table configurations.
|
||||||
|
*/
|
||||||
|
class Storage {
|
||||||
|
constructor(path) {
|
||||||
|
this.path = path;
|
||||||
|
this.ready = false; // Async Actions still need to happen
|
||||||
|
|
||||||
|
/** @type {Array<Albums>} */
|
||||||
|
this.albums = [];
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the Storage Instance.
|
||||||
|
* @async
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
async init() {
|
||||||
|
const filepath = new Filepath(path);
|
||||||
|
this.knownFiles = await filepath.getValidFiles();
|
||||||
|
|
||||||
|
this.ready = true; // All prerequisite Async has been done.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Goes Through all Known Songs and
|
||||||
|
* Creates Object Representatinos of all of them.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
parseSongList() {
|
||||||
|
const files = this.knownFiles;
|
||||||
|
|
||||||
|
// Need to Iterate over every song, find the name of the album and create an album with that instance.
|
||||||
|
// Store the album in some array so we know what albums exist and have a method to check whether the album has been
|
||||||
|
// created or not. Once that is done we can then create a Song based of that, and add it to the album.
|
||||||
|
|
||||||
|
// The end result should be an album class with all the properties filled in
|
||||||
|
// with attention put towards this.songs which would be an array of Song classes.
|
||||||
|
|
||||||
|
files.forEach(async path => {
|
||||||
|
const song = new Song(path, true);
|
||||||
|
|
||||||
|
const albumName = song.metadata.common.album;
|
||||||
|
|
||||||
|
if (!albumExists(albumName)) {
|
||||||
|
const album = new Album(albumName);
|
||||||
|
album.addSong(song);
|
||||||
|
|
||||||
|
|
||||||
|
this.albums.push(album)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if album is already present in List of known Albums.
|
||||||
|
* @param {*} name
|
||||||
|
*/
|
||||||
|
function albumExists(name) {
|
||||||
|
/// Please Write a Better version of this later.
|
||||||
|
let exists = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < self.albums.length; i++) {
|
||||||
|
if (self.albums[i].name === name) {
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Representation of an Album of Songs
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Album {
|
||||||
|
/** @param {String} name */
|
||||||
|
constructor(name) {
|
||||||
|
// Properties Here are based off what is commonly found within Mp3 Tags.
|
||||||
|
|
||||||
|
/** @type {String} */
|
||||||
|
this.name
|
||||||
|
|
||||||
|
/** @type {Array<Song>} */
|
||||||
|
this.songs = [];
|
||||||
|
|
||||||
|
/** Album Artist */
|
||||||
|
this.artist = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds Class Representation of a Song to an Album Class
|
||||||
|
* @param {Song} song
|
||||||
|
*/
|
||||||
|
addSong(song) {
|
||||||
|
this.songs.push(song);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a Song Class from the Album
|
||||||
|
* @param {String} path
|
||||||
|
*/
|
||||||
|
removeSong(path) {
|
||||||
|
console.error("This feature is unimplimented.")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Reference in New Issue