|
| 1 | +# Music Streaming Platform 🎵🎧 |
| 2 | + |
| 3 | +## Мрежово програмиране |
| 4 | + |
| 5 | +Тази задача има за цел да ви запознае с разработката на клиент-сървър приложения чрез създаване на опростена платформа за стрийминг на музика. |
| 6 | +Музиката е универсален език, който свързва хора от различни култури и поколения. С развитието на интернет и мобилните устройства, приложенията за streaming музика като Spotify и Apple Music се превърнаха в неразделна част от ежедневието ни. |
| 7 | + |
| 8 | +В рамките на задачата ще разработите **клиент-сървър приложение**, при което: |
| 9 | +- Сървърът съхранява и управлява плейлисти и песни; |
| 10 | +- Клиентите комуникират със сървъра чрез текстови команди. |
| 11 | + |
| 12 | +## Music Streaming Platform Client |
| 13 | + |
| 14 | +Всеки клиент: |
| 15 | +- може да създава плейлисти |
| 16 | +- може да добавя песни към плейлисти |
| 17 | +- може да търси плейлисти по име |
| 18 | +- може да преглежда песните в дадена плейлиста |
| 19 | +- може да харесва и "отхаресва" песни |
| 20 | +- може да прекрати връзката със сървъра по всяко време. |
| 21 | + |
| 22 | +## Music Streaming Platform Server |
| 23 | + |
| 24 | +Сървърът: |
| 25 | +- трябва да обслужва множество клиенти едновременно |
| 26 | +- получава команди от клиентите и връща резултат |
| 27 | +- управлява плейлисти, песни и броя на харесванията. |
| 28 | + |
| 29 | +Имплементирайте следния конструктор: |
| 30 | + |
| 31 | +```java |
| 32 | +public MusicStreamingServer(int port, PlaylistRepository playlistRepository) |
| 33 | +``` |
| 34 | + |
| 35 | +Както и следните методи: |
| 36 | + |
| 37 | +```java |
| 38 | +public void start() - стартира сървъра на зададения в конструктора порт |
| 39 | +public void stop() - спира сървъра и зачиства ресурсите |
| 40 | +``` |
| 41 | + |
| 42 | +## Команди |
| 43 | + |
| 44 | +### create-playlist |
| 45 | + |
| 46 | +``` |
| 47 | +create-playlist <playlist_name> |
| 48 | +``` |
| 49 | + |
| 50 | +Създава нова плейлиста. |
| 51 | + |
| 52 | +Ограничения: |
| 53 | +- името е една дума (без интервали); |
| 54 | +- не може да съществуват две плейлисти с едно и също име. |
| 55 | + |
| 56 | +### add-song |
| 57 | + |
| 58 | +``` |
| 59 | +add-song <playlist_name> <song_title> <artist_name> <duration> |
| 60 | +``` |
| 61 | + |
| 62 | +Добавя песен към плейлиста. |
| 63 | + |
| 64 | +Ограничения: |
| 65 | +- `song_title` и `artist_name` са една дума; |
| 66 | +- `duration` е цяло число (секунди); |
| 67 | +- една и съща песен (заглавие + артист) не може да бъде добавяна два пъти. |
| 68 | + |
| 69 | +### like-song |
| 70 | + |
| 71 | +``` |
| 72 | +like-song <playlist_name> <song_title> <artist_name> |
| 73 | +``` |
| 74 | + |
| 75 | +Увеличава броя харесвания с 1. |
| 76 | + |
| 77 | +### unlike-song |
| 78 | + |
| 79 | +``` |
| 80 | +unlike-song <playlist_name> <song_title> <artist_name> |
| 81 | +``` |
| 82 | + |
| 83 | +Намалява броя харесвания с 1 (минимум 0). |
| 84 | + |
| 85 | +### list-playlists |
| 86 | + |
| 87 | +``` |
| 88 | +list-playlists |
| 89 | +``` |
| 90 | + |
| 91 | +Връща списък с всички плейлисти. |
| 92 | + |
| 93 | +### get-playlist |
| 94 | + |
| 95 | +``` |
| 96 | +get-playlist <playlist_name> |
| 97 | +``` |
| 98 | + |
| 99 | +Връща детайлна информация за плейлиста. |
| 100 | + |
| 101 | +### disconnect |
| 102 | + |
| 103 | +``` |
| 104 | +disconnect |
| 105 | +``` |
| 106 | + |
| 107 | +Прекратява връзката със сървъра. |
| 108 | + |
| 109 | +## Примерна сесия |
| 110 | + |
| 111 | +```bash |
| 112 | +create-playlist MyFavorites |
| 113 | +{"status":"OK","message":"Playlist MyFavorites created successfully."} |
| 114 | + |
| 115 | +add-song MyFavorites Imagine John-Lennon 183 |
| 116 | +{"status":"OK","message":"Song Imagine by John-Lennon added successfully."} |
| 117 | + |
| 118 | +like-song MyFavorites Imagine John-Lennon |
| 119 | +{"status":"OK","message":"Song Imagine by John-Lennon liked. Likes: 1"} |
| 120 | + |
| 121 | +get-playlist MyFavorites |
| 122 | +{"status":"OK","playlist":{"name":"MyFavorites","songs":[{"title":"Imagine","artist":"John-Lennon","duration":183,"likes":1}]}} |
| 123 | +``` |
| 124 | + |
| 125 | +## Интерфейси |
| 126 | + |
| 127 | +Имплементирайте следния интерфейс като създадете клас `InMemoryPlaylistRepository` с конструктор по подразбиране: |
| 128 | + |
| 129 | +```java |
| 130 | +package bg.sofia.uni.fmi.mjt.music.server.repository; |
| 131 | + |
| 132 | +import bg.sofia.uni.fmi.mjt.music.server.model.Playlist; |
| 133 | + |
| 134 | +import java.util.Collection; |
| 135 | + |
| 136 | +public interface PlaylistRepository { |
| 137 | + |
| 138 | + /** |
| 139 | + * Creates a new playlist with the given name. |
| 140 | + * |
| 141 | + * @param playlistName the name of the playlist to be created. |
| 142 | + * The name must be a single word (no whitespaces). |
| 143 | + * @throws PlaylistAlreadyExistsException if a playlist with the given name |
| 144 | + * already exists. |
| 145 | + */ |
| 146 | + void createPlaylist(String playlistName) throws PlaylistAlreadyExistsException; |
| 147 | + |
| 148 | + /** |
| 149 | + * Adds a new song to an existing playlist. |
| 150 | + * |
| 151 | + * @param playlistName the name of the playlist to which the song will be added. |
| 152 | + * @param songTitle the title of the song. |
| 153 | + * @param artistName the name of the artist. |
| 154 | + * @param duration the duration of the song in seconds. |
| 155 | + * @throws PlaylistNotFoundException if the playlist with the given name |
| 156 | + * does not exist. |
| 157 | + * @throws SongAlreadyExistsException if a song with the same title and artist |
| 158 | + * already exists in the playlist. |
| 159 | + */ |
| 160 | + void addSong(String playlistName, String songTitle, String artistName, int duration) |
| 161 | + throws PlaylistNotFoundException, SongAlreadyExistsException; |
| 162 | + |
| 163 | + /** |
| 164 | + * Increases the number of likes of a given song in the playlist by 1. |
| 165 | + * |
| 166 | + * @param playlistName the name of the playlist. |
| 167 | + * @param songTitle the title of the song. |
| 168 | + * @param artistName the name of the artist. |
| 169 | + * @return the updated number of likes for the song. |
| 170 | + * @throws PlaylistNotFoundException if the playlist does not exist. |
| 171 | + * @throws SongNotFoundException if the song does not exist in the playlist. |
| 172 | + */ |
| 173 | + int likeSong(String playlistName, String songTitle, String artistName) |
| 174 | + throws PlaylistNotFoundException, SongNotFoundException; |
| 175 | + |
| 176 | + /** |
| 177 | + * Decreases the number of likes of a given song in the playlist by 1. |
| 178 | + * The number of likes cannot be less than 0. |
| 179 | + * |
| 180 | + * @param playlistName the name of the playlist. |
| 181 | + * @param songTitle the title of the song. |
| 182 | + * @param artistName the name of the artist. |
| 183 | + * @return the updated number of likes for the song. |
| 184 | + * @throws PlaylistNotFoundException if the playlist does not exist. |
| 185 | + * @throws SongNotFoundException if the song does not exist in the playlist. |
| 186 | + */ |
| 187 | + int unlikeSong(String playlistName, String songTitle, String artistName) |
| 188 | + throws PlaylistNotFoundException, SongNotFoundException; |
| 189 | + |
| 190 | + /** |
| 191 | + * Retrieves the names of all existing playlists. |
| 192 | + * |
| 193 | + * @return a collection containing the names of all playlists. |
| 194 | + * If no playlists exist, an empty collection is returned. |
| 195 | + */ |
| 196 | + Collection<String> getAllPlaylists(); |
| 197 | + |
| 198 | + /** |
| 199 | + * Retrieves detailed information about a playlist with the given name. |
| 200 | + * |
| 201 | + * @param playlistName the name of the playlist to retrieve. |
| 202 | + * @return the {@link Playlist} object containing information about the playlist |
| 203 | + * and all of its songs. |
| 204 | + * @throws PlaylistNotFoundException if the playlist does not exist. |
| 205 | + */ |
| 206 | + Playlist getPlaylist(String playlistName) throws PlaylistNotFoundException; |
| 207 | + |
| 208 | +} |
| 209 | +``` |
| 210 | + |
| 211 | +## Модели |
| 212 | + |
| 213 | +```java |
| 214 | +public record Playlist(String name, Set<Song> songs) {} |
| 215 | +public record Song(String title, String artist, int duration, int likes) {} |
| 216 | +``` |
| 217 | + |
| 218 | +- Две песни са еднакви, ако заглавието и артистът съвпадат. |
| 219 | + |
| 220 | +## Валидации |
| 221 | + |
| 222 | +Уверете се, че всички команди са валидирани и връщат съобщение за грешка, ако форматът на командата не е валиден. |
| 223 | + |
| 224 | +Пример: |
| 225 | + |
| 226 | +``` |
| 227 | +add-song MyFavorites |
| 228 | +``` |
| 229 | + |
| 230 | +Отговор: |
| 231 | + |
| 232 | +```json |
| 233 | +{"status":"ERROR","message":"Usage: add-song <playlist_name> <song_title> <artist_name> <duration>"} |
| 234 | +``` |
| 235 | + |
| 236 | +## Тестване |
| 237 | + |
| 238 | +⭐ Тествайте ръчно имплементацията, първо с един, а после с няколко паралелно свързани клиента, и се убедете, че работи коректно. |
| 239 | + |
| 240 | +⭐ Писането на автоматични тестове за тази задача е по ваш избор, но съветваме всеки да пробва, тъй като ще ви е полезно и за курсовите проекти. |
| 241 | + |
| 242 | +👉 Подсказка: Припомнете си различните имплементации на Echo Client-Server. Можем ли да ги превърнем в Music Streaming Platform 🎵🎧 Client-Server приложение? |
| 243 | + |
| 244 | +👉 Подсказка: Решението на тази задача ще ви улесни изключително много при разработката на курсовите ви проекти, защото всички те представляват приложения тип клиент-сървър, като сървърът обслужва много потребители едновременно. |
| 245 | + |
| 246 | +## Примерна структура на проекта |
| 247 | + |
| 248 | +Добра практика при създаването на приложения тип клиент-сървър е да отделяте клиента и сървъра в отделни проекти. Това предотвратява грешки от типа, класове/интерфейси от клиента да се ползват от сървъра, или обратно. Също така, в реална ситуация, бихме искали да пакетираме и разпространяваме поотделно клиентската и сървърната част на нашето приложение. Като минимум, отделете имплементацията на клиента и сървъра в отделни пакети. |
| 249 | + |
| 250 | +В грейдъра качете папки `src` и `test`, ако имате тестове (или техен общ `zip` архив). |
| 251 | + |
| 252 | +``` |
| 253 | +src |
| 254 | +└─ bg.sofia.uni.fmi.mjt.music |
| 255 | + ├── client |
| 256 | + │ └── MusicStreamingClient.java |
| 257 | + ├── server |
| 258 | + │ ├── MusicStreamingServer.java |
| 259 | + │ ├── model |
| 260 | + │ │ ├── Playlist.java |
| 261 | + │ │ ├── Song.java |
| 262 | + │ │ └── (...) |
| 263 | + │ ├── repository |
| 264 | + │ │ ├── InMemoryPlaylistRepository.java |
| 265 | + │ │ ├── PlaylistRepository.java |
| 266 | + │ │ ├── exception |
| 267 | + │ │ │ ├── PlaylistAlreadyExistsException.java |
| 268 | + │ │ │ ├── PlaylistNotFoundException.java |
| 269 | + │ │ │ ├── SongAlreadyExistsException.java |
| 270 | + │ │ │ └── SongNotFoundException.java |
| 271 | + │ │ └── (...) |
| 272 | + │ └── (...) |
| 273 | + └── (...) |
| 274 | +``` |
| 275 | + |
| 276 | +В грейдъра качете папките `src` и `test`, ако имате тестове (или техен общ архив). |
0 commit comments