diff --git a/Dockerfile b/Dockerfile index 1362e6153f2313012dc315390d278b25dde5288e..01cc4375a4d2c72844b0b78cfaf622fbc2dfd7a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,4 +5,5 @@ RUN apt-get install -y libpq-dev \ && docker-php-ext-install pdo pdo_pgsql RUN a2enmod rewrite \ && service apache2 restart +RUN apt install -y ffmpeg #COPY src/web .htaccess /var/www/html/ \ No newline at end of file diff --git a/src/sql/initial-data.sql b/src/sql/initial-data.sql index cc38f674e4b99892ac371516c7a47c505bf423df..ff3b101946b889826a54311f7a94630c4f0a998a 100644 --- a/src/sql/initial-data.sql +++ b/src/sql/initial-data.sql @@ -29,6 +29,7 @@ create table if not exists music ( album_id int not null, genre varchar(255), year int, + duration int not null, owner_account_id int, music_filename varchar(255), foreign key (album_id) references album(album_id), diff --git a/src/web/music/music.php b/src/web/music/music.php index 3e9ada1e5e143fae1016f059b718e5d38fe94846..b4888f9e1c8a2d512e4a29c2262813feee38537b 100644 --- a/src/web/music/music.php +++ b/src/web/music/music.php @@ -1,5 +1,12 @@ <?php +function getDuration($filename): int { + $dur = shell_exec("ffmpeg -i $filename 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//"); + $dur = explode(':', $dur); + + return (int) $dur[0] * 3600 + (int) $dur[1] * 60 + (int) $dur[2]; +} + function addMusic(string $accountId, string $title, string $genre, string $year, string $albumId): int { $fileName = $_FILES['file']['name']; $fileName = str_replace(' ', '', $fileName); @@ -30,12 +37,15 @@ function addMusic(string $accountId, string $title, string $genre, string $year, $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); curl_reset($curl); + $duration = getDuration($_FILES['file']['tmp_name']); + if ($http_code == 200) { - $query = 'INSERT INTO music (title, album_id, genre, year, owner_account_id, music_filename) - VALUES(:title, :albumId, :genre, :year, :accountId, :fileName)'; + $query = 'INSERT INTO music (title, album_id, genre, year, duration, owner_account_id, music_filename) + VALUES(:title, :albumId, :genre, :year, :duration, :accountId, :fileName)'; $params = [ 'title' => $title, 'year' => $year, + 'duration' => $duration, 'albumId' => $albumId, 'genre' => $genre, 'fileName' => $fileName, diff --git a/src/web/presentation/music/info/albumInfo.php b/src/web/presentation/music/info/albumInfo.php index 04325fc8fd2b3d7d06aefea30466d0416ffc0b11..d1078fb4c1a980ae05b9d1edade08dfd35ff253b 100644 --- a/src/web/presentation/music/info/albumInfo.php +++ b/src/web/presentation/music/info/albumInfo.php @@ -2,4 +2,72 @@ if ($_SERVER['REQUEST_METHOD'] == 'GET') { require 'albumInfo.view.php'; +} else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + $data = json_decode(file_get_contents('php://input'), true); + $query = execSelect("SELECT owner_account_id, music_filename FROM music WHERE music_id = :id", ['id' => $data['id']]); + $accountId = $query[0]['owner_account_id']; + $fileName = $query[0]['music_filename']; + + $params = http_build_query(array( + 'owner' => $accountId, // account id, + 'fileType' => 'music', + 'fileName' => $fileName + )); + + $curl = curl_init('object-storage:80/object?'.$params); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + $result = curl_exec($curl); + + if (!curl_errno($curl) && curl_getinfo($curl, CURLINFO_HTTP_CODE) == 200) { + $contentType = curl_getinfo($curl, CURLINFO_CONTENT_TYPE); + $data = 'data:'.$contentType.';base64,'.base64_encode($result); + echo json_encode(['data' => $data]); + } + curl_close($curl); +} + +function secondsToMinutes($duration): string { + $minutes = floor($duration / 60); + $seconds = $duration % 60; + + if ($seconds < 10) { + $seconds = '0'.$seconds; + } + + return $minutes.':'.$seconds; +} + +function createListItem($class, $id, $title, $duration): void { + echo '<li class="'.$class.'">'; + echo ' <p class="music-title" id="music-title">'.$title.'</p>'; + echo ' <div class="music-sub-item">'; + echo ' <p style="display: none" id="music-id">'.$id.'</p>'; + echo ' <p class="music-duration">'.secondsToMinutes($duration).'</p>'; + echo ' </div>'; + echo '</li>'; +} + +function populateList($album_id): void { + $list = execSelect("SELECT music_id, title, duration FROM music WHERE album_id = :album_id", ['album_id' => $album_id]); + + if (count($list) == 0) { + return; + } + + if (count($list) == 1) { + createListItem('music-single-item', $list[0]['music_id'], $list[0]['title'], $list[0]['duration']); + return; + } + + // top item + createListItem('music-item-top', $list[0]['music_id'], $list[0]['title'], $list[0]['duration']); + + $midItems = array_slice($list, 1, count($list) - 2); + + foreach ($midItems as $item) { + createListItem('music-item-mid', $item['music_id'], $item['title'], $item['duration']); + } + + // bottom item + createListItem('music-item-bot', $list[count($list) - 1]['music_id'], $list[count($list) - 1]['title'], $list[count($list) - 1]['duration']); } diff --git a/src/web/presentation/music/info/albumInfo.view.php b/src/web/presentation/music/info/albumInfo.view.php index 621ac4c32d3fcfa7040a8e55daf2d5ba698ff60b..48bc322ef2706693b4e144e77675ee8d7046c7dc 100644 --- a/src/web/presentation/music/info/albumInfo.view.php +++ b/src/web/presentation/music/info/albumInfo.view.php @@ -1,22 +1,62 @@ +<?php + +require_once 'util/album-finder.php'; +require_once 'util/account-finder.php'; + +$name = ""; +$artist = ""; +$year = ""; + +function populateFields($id): void { + global $name, $artist, $year; + + $result = execSelect("SELECT * FROM album WHERE album_id = :id", ['id' => $id]); + + if (count($result) == 0) { + return; + } + + $name = $result[0]['name']; + $artist = getAccountName($result[0]['owner_account_id']); + $year = $result[0]['year']; +} + +?> + <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Artist - Album Title</title> - <link rel="stylesheet" href="presentation/music/info/css/albumInfo.css"> + <link rel="stylesheet" href="/presentation/music/info/css/albumInfo.css"> <link rel="preconnect" href="https://fonts.googleapis.com%22%3E/"> <link rel="preconnect" href="https://fonts.gstatic.com/" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet"> </head> <body> +<script src="/presentation/music/info/js/albumInfo.js" defer></script> +<audio id="hidden-audio" src=""></audio> <div class="img-container"> - <img src="presentation/music/info/img/defalbum.jpg" alt="Album"> + <img src="<?php echo getAlbumImage() ?>" alt="Album"> </div> -<div id="album-info"> - <p id="artist-title">Artist - Album Title</p> - <div class="more-info"> - <p id="year">Year</p> + <div id="album-info"> + <?php + $id = $_GET['id'] ?? null; + if (is_numeric($id)) { + populateFields($id); + } + ?> + <p id="artist-title"><?php echo $artist.' - '.$name ?></p> + <div class="more-info"> + <p id="year"><?php echo $year ?></p> + </div> + </div> + <div id="music-list-d"> + <ol id="music-list"> + <?php + populateList($id); + ?> + </ol> </div> -</div> </body> </html> \ No newline at end of file diff --git a/src/web/presentation/music/info/css/albumInfo.css b/src/web/presentation/music/info/css/albumInfo.css index 912971c38408ed3e9c9484d162849549c8f9bb31..67c4c5eb6e1071efc68c461cd53b6e8df27ec2e4 100644 --- a/src/web/presentation/music/info/css/albumInfo.css +++ b/src/web/presentation/music/info/css/albumInfo.css @@ -26,4 +26,59 @@ html { #artist-title { font-size: 36px; margin-bottom: 0; +} + +#music-list-d { + text-align: center; + width: 100%; +} + +#music-list { + margin: auto; + width: 640px; + padding-left: 0; +} + +#music-list li { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 12px; + border: 1px solid #e0e0e0; + cursor: pointer; +} + +#hidden-audio { + display: none; +} + +.music-item-top { + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} + +.music-item-mid { + border-top: none !important; +} + +.music-item-bot { + border-top: none !important; + border-bottom-left-radius: 5px; + border-bottom-right-radius: 5px; +} + +.music-single-item { + border-radius: 5px; +} + +.music-sub-item { + display: flex; +} + +.music-play { + display: flex; + flex-direction: row; + justify-content: space-between; + margin-right: 8px; } \ No newline at end of file diff --git a/src/web/presentation/music/info/js/albumInfo.js b/src/web/presentation/music/info/js/albumInfo.js new file mode 100644 index 0000000000000000000000000000000000000000..05cd95a9777ff1a09c202b8d240fcccf71e0fe9c --- /dev/null +++ b/src/web/presentation/music/info/js/albumInfo.js @@ -0,0 +1,29 @@ +const list = document.querySelector('#music-list').getElementsByTagName('li'); + +for (let item of list) { + item.addEventListener('click', (e) => { + e.preventDefault(); + + let id = item.querySelector('#music-id').innerHTML; + + let url = '/album'; + let xhr = new XMLHttpRequest(); + + let data = { + id: id + } + + xhr.open('POST', url, true); + xhr.setRequestHeader('Content-Type', 'application/json'); + xhr.onreadystatechange = function() { + if (xhr.readyState === 4 && xhr.status === 200) { + let audio = JSON.parse(xhr.responseText); + let audioPlayer = document.querySelector('#hidden-audio'); + audioPlayer.src = audio.data; + audioPlayer.play(); + } + } + + xhr.send(JSON.stringify(data)); + }); +} \ No newline at end of file