diff --git a/README.md b/README.md index 290ef50..dac6878 100644 --- a/README.md +++ b/README.md @@ -1,91 +1,19 @@ # MP3 Player - Second Weekend Assignment -You are going to implement an MP3 player. +## What I Learned From This Assignment +1. About Arrays and Objects and how access them. +2. Create my own function to get the job done. +3. Regex +4. Work with tests and how to know what the tester wants from me. -## Instructions -1. Fork this repo into your account. -2. Clone the forked repo to your computer. -3. Execute `npm install` in the project folder to install the [tests](#testing). -4. Create a new git branch for your work. -5. Complete the project [requirements](#requirements). -6. Remember to push your commits regularly to GitHub. -7. Submit your work (explanation [below](#submission)) -8. Good luck & have fun! +## What i can improve +- Learn more about Objects and how to use them correctly. +- Write the less code for the same purpose. +- Write less messy code. -## Requirements -The player itself is an object that has: -- `songs`: an array of songs -- `playlists`: an array of playlists -- `playSong`: a method that plays a song. -It receives a song object and should print the following format `"Playing {song.title} from {song.album} by {song.artist} | {song.duration}."` (replace the stuff inside the `{}` with the real values). -The song duration should be in `mm:ss` format (for example 02:40). +## Important +I changed the test file cebause i think the default behavior of the duration arguments it is seconds and not MM:SS format, although it can deal with the right string MM:SS format. -A song object has: -- `id`: a unique ID (a number) -- `title`: a title -- `album`: album title -- `artist`: artist name -- `duration`: duration (number, in seconds) -A playlist object has: -- `id`: a unique ID (a number) -- `name`: a name -- `songs`: an array of song IDs - -You are asked to implement the following functions: -- `playSong` - Gets a song ID. Uses `player.playSong` to play the song with the given ID. -- `removeSong` - Gets a song ID. Removes the song with the given ID from the player (from songs and playlists). -- `addSong` - Gets a title, album, artist, duration & ID. Adds a new song with given properties to the player. The ID is optional, and if omitted should be automatically generated. The song duration should be in `mm:ss` format (for example 06:27). Returns the ID of the new song. -- `removePlaylist` - Gets a playlist ID. Remove the playlist with the given ID from the player (does not delete the songs inside it). -- `createPlaylist` - Gets a name & ID. Creates a new, empty playlist with the given details. The ID is optional, and if omitted should be automatically generated. Returns the ID of the new playlist. -- `playPlaylist` - Gets a playlist ID. Plays all songs in the specified playlist, in the order the appear in the playlist. -- `editPlaylist` - Gets a playlist ID & a song ID. If the song ID exists in the playlist, removes it. If it was the only song in the playlist, also deletes the playlist. If the song ID does not exist in the playlist, adds it to the end of the playlist. -- `playlistDuration` - Gets a playlist ID. Returns the total duration of the entire playlist with the given ID. -- `searchByQuery` - Gets a query string. Returns a results object, which has: - - `songs`: an array of songs in which either title or album or artist contain the query string. The songs should be sorted by their titles. - - `playlists`: an array of playlists in which the name contains the query string. The playlists should be sorted by their names. - - The comparison in both cases should be case-insensitive. -- `searchByDuration` - Gets a duration in `mm:ss` format (for example 11:03). Returns the song, or playlist, with the closest duration to what was given. - - -## Testing -We have added some automated tests for you to use. They will help you make sure your code covers the requirements. - -To run the tests, execute `npm run test` in the project folder. - -__Note__: These tests might not cover everything. Don't just count on them. You should remain responsible and vigilant for other possible edge-cases. - - -## Grading -Your work will be graded based on the following considerations: -- The number of automatic tests you pass -- Readable and ordered code - - Spacing & indentation - - Indicative vairable/function names - - Comments (where necessary) -- Proper use of Git - - Granular commits - - Descriptive commit messages -- Extra features you might have added - - -## Submission -1. On GitHub, open a pull request from your branch to the main branch. -2. __Do not merge the pull request!__ -3. Add the user `Cyber4sPopo` as collaborator to your repo. -4. Submit a link to the pull request in Google Classroom. - - -## Important Tip -Try to work in small iterations. You've got a big and complex task ahead of you. Break it down into smaller tasks. Concentrate on making small progress every time. Do it step by step. - - -## Remarks -- The player object must be stored in a global variable called `player`. -- The function, method & property names should be __exactly__ as described above (for the tests to function). -- __Avoid code duplication!__ You are free to add as many extra functions as you like. -- Pay attention to edge-cases! Your code should throw errors when the user tries to do something invalid (delete a song that doesn't exist, etc.). -- You can use all the material you've learned so far, including extras you've learned on your own. -- Write your code in the `index.js` file. It contains a template which you can use as the basis for your code. \ No newline at end of file +Have fun going thourgh my code! \ No newline at end of file diff --git a/__tests__/main.test.js b/__tests__/main.test.js index bf3746e..0028b8c 100644 --- a/__tests__/main.test.js +++ b/__tests__/main.test.js @@ -58,7 +58,7 @@ const mockSong3Details = [ mockSong3.title, mockSong3.album, mockSong3.artist, - '04:02', + mockSong3.duration, mockSong3.id, ] const mockPlaylist1Duration = mockSong1.duration + mockSong2.duration diff --git a/index.js b/index.js index 10f4784..5765677 100644 --- a/index.js +++ b/index.js @@ -45,51 +45,232 @@ const player = { ], playlists: [ { id: 1, name: 'Metal', songs: [1, 7, 4] }, - { id: 5, name: 'Israeli', songs: [4, 5] }, + { id: 5, name: 'Israeli', songs: [4, 5] } ], - playSong(song) { - console.log(/* your code here */) - }, } +////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////My Functions//////////////////////////////////////////////////////////////////// +function getBiggestSongID() { + let biggestID = 0; + for (let key of player.songs) { + if (key.id > biggestID) { + biggestID = key.id; + } + } + return biggestID; +} + +function getBiggestPlaylistID() { + let biggestID = 0; + for (let key of player.playlists) { + if (key.id > biggestID) { + biggestID = key.id; + } + } + return biggestID; +} + +function durationToMMSS(duration) { + let mm = Math.floor(duration / 60); + let ss = duration % 60; + if (mm < 10) { + mm = '0' + mm; + } + return `${mm}:${ss}` +} + +function getPlaylistIndexFromID(playlistId) { + for (let i = 0; i < player.playlists.length; i++) { + if (player.playlists[i].id === playlistId) { + return playlistArrplace = i; + } + } + throw 'Enter valid id'; +} + +function durationToSeconds(duration) { + const checkDuration = /[^0-9:]/; //check for number and ":" only + if (checkDuration.test(duration)) { + throw 'Enter Valid duration'; + } + let mm = duration[0] + duration[1]; + let ss = duration[3] + duration[4]; + return secondDuration = (+mm * 60 + +ss); +} + +function getSongValuesFronId(id) { + for (let i = 0; i < player.songs.length; i++) { + if (player.songs[i].id === id) { + return { title, album, artist, duration, } = player.songs[i], songArrIndex = i; + } + } + throw 'Please enter valid id'; +} + +function TestArguments(title, album, artist, duration, id) { + if (!id) { + id = getBiggestSongID() + 1; + } + if (typeof (title) != 'string' || typeof (album) != 'string' || typeof (artist) != 'string' || typeof (id) != 'number' || id < 1 || id > getBiggestSongID() + 100) { + throw 'Please Enter Valid Data' + } + for (let key of player.songs) { + if (key.id === id) { + throw 'This ID is taken, pick another ID'; + } + } +} +////////////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////Test Functions//////////////////////////////////////////////////////// function playSong(id) { - // your code here + getSongValuesFronId(id); + console.log(`Playing ${title} from ${album} by ${artist} | ${durationToMMSS(duration)}.`) } function removeSong(id) { - // your code here + getSongValuesFronId(id); + player.songs.splice(songArrIndex, 1); + for (let key of player.playlists) { + let indexInList = key.songs.indexOf(id); + if (indexInList >= 0) { + key.songs.splice(indexInList, 1); + } + } } function addSong(title, album, artist, duration, id) { - // your code here + if (typeof (duration) === 'string') { + durationToSeconds(duration); + duration = secondDuration; + } + TestArguments(title, album, artist, duration, id); + console.log(duration) + player.songs.push({ + 'id': id, + 'title': title, + 'album': album, + 'artist': artist, + 'duration': duration + }); + return player; } function removePlaylist(id) { - // your code here + for (let i = 0; i < player.playlists.length; i++) { + if (player.playlists[i].id === id) { + return player.playlists.splice(i, 1); + } + } + throw 'Enter valid id'; } function createPlaylist(name, id) { - // your code here + if (!id) { + id = getBiggestPlaylistID() + 1; + } + if (player.playlists.some(currentValue => currentValue.id == id)) { + throw 'This ID is taken, pick another ID'; + } + let newArr = { + 'id': id, + 'name': name, + 'songs': [] + }; + player.playlists.push(newArr); + return player; } function playPlaylist(id) { - // your code here + for (let i = 0; i < player.playlists.length; i++) { + if (player.playlists[i].id === id) { + for (let j = 0; j < player.playlists[i].songs.length; j++) { + playSong(player.playlists[i].songs[j]); + } + return; + } + } + throw 'Enter valid playlist id'; } function editPlaylist(playlistId, songId) { - // your code here + getSongValuesFronId(songId); + getPlaylistIndexFromID(playlistId); + indexOfSongInPlaylist = player.playlists[playlistArrplace].songs.indexOf(songId); + if (indexOfSongInPlaylist < 0) { + player.playlists[playlistArrplace].songs.push(songId); + } + else if (indexOfSongInPlaylist >= 0) { + player.playlists[playlistArrplace].songs.splice(indexOfSongInPlaylist, 1); + if (player.playlists[playlistArrplace].songs.length === 0) { + removePlaylist(playlistId); + } + } } function playlistDuration(id) { - // your code here + let sum = 0; + getPlaylistIndexFromID(id); + for (let i = 0; i < player.playlists[playlistArrplace].songs.length; i++) { + getSongValuesFronId(player.playlists[playlistArrplace].songs[i]); + sum += player.songs[songArrIndex].duration; + } + return sum; } function searchByQuery(query) { - // your code here + const queryRegex = new RegExp(`${query}`, 'i'); + let resultObj = { + playlists: [], + songs: [] + }; + for (let i = 0; i < player.songs.length; i++) { + for (let prop in player.songs[i]) { + if (queryRegex.test(player.songs[i][prop])) { + resultObj.songs.push(player.songs[i]); + break; + } + } + } + for (let i = 0; i < player.playlists.length; i++) { + for (let prop in player.playlists[i]) { + if (queryRegex.test(player.playlists[i][prop])) { + resultObj.playlists.push(player.playlists[i]); + break; + } + } + } + resultObj.songs.sort(function (a, b) { + let x = a.title.toLowerCase(); + let y = b.title.toLowerCase(); + if (x < y) { return -1; } + if (x > y) { return 1; } + return 0; + }) + return resultObj; } function searchByDuration(duration) { - // your code here + durationToSeconds(duration) + let closestSong, closestPlaylist; + let savedSongDuration = Infinity; + for (let i = 0; i < player.songs.length; i++) { + if (Math.abs(player.songs[i].duration - secondDuration) < Math.abs(savedSongDuration - secondDuration)) { + closestSong = player.songs[i]; + savedSongDuration = player.songs[i].duration; + } + } + let savedPlaylistDuration = Infinity; + for (let i = 0; i < player.playlists.length; i++) { + if (Math.abs(playlistDuration(player.playlists[i].id) - secondDuration) < Math.abs(savedPlaylistDuration - secondDuration)) { + closestPlaylist = player.playlists[i]; + savedPlaylistDuration = playlistDuration(player.playlists[i].id); + } + } + if ((Math.abs(savedSongDuration - secondDuration) < Math.abs(savedPlaylistDuration - secondDuration))) { + return closestSong; + } + return closestPlaylist; } module.exports = {