- ์Œ์•… ํ”Œ๋ ˆ์ด์–ด (๊น”๋”ํ•œ ๋””์ž์ธ)

PC ์ตœ์ ํ™”๋ผ ๋ชจ๋ฐ”์ผ์—์„  ๋‚˜์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค!

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

<div id="music-widget-root" class="fixed-music-widget">
    <div id="widget-container" class="widget-container">
        
        <button class="toggle-minimize" onclick="toggleMinimize()" title="์ ‘๊ธฐ/ํŽด๊ธฐ">
            <i id="min-icon" class="fa-solid fa-minus"></i>
        </button>

        <div class="image-rotation-wrapper" onclick="togglePlaylist()">
            <div id="image-main" class="rotated-image-area">
                <img src="https://i.postimg.cc/0N1L1YWy/images.jpg" alt="Fixed Cover">
            </div>
        </div>

        <div class="track-meta">
            <div id="meta-name">Nothing Now</div>
            <div id="meta-user">Select a song</div>
        </div>

        <div class="player-bottom">
            <div class="nav-btns">
                <button onclick="playPrev()"><i class="fa-solid fa-backward-step"></i></button>
                <button onclick="handleToggle()" id="main-play-btn" class="mini-play"><i class="fa-solid fa-play"></i></button>
                <button onclick="playNext()"><i class="fa-solid fa-forward-step"></i></button>
            </div>

            <div class="control-row-final">
                <i class="fa-solid fa-volume-off v-icon"></i>
                <div class="vol-line">
                    <input type="range" id="vol-range" min="0" max="1" step="0.01" value="0.2" oninput="changeVol()">
                </div>
                <i class="fa-solid fa-volume-high v-icon"></i>
                <button onclick="handleLoop()" id="loop-btn-final" title="๋ฐ˜๋ณต ์žฌ์ƒ">
                    <i class="fa-solid fa-arrows-rotate"></i>
                </button>
            </div>
        </div>

        <div id="list-panel" class="list-panel-style">
            <div class="list-header" onclick="togglePlaylist()">Playlist <i class="fa-solid fa-chevron-down"></i></div>
            <ul id="list-render-target"></ul>
        </div>
    </div>
</div>

<style>
    .fixed-music-widget { position: fixed; top: 20px; left: 20px; z-index: 10000; font-family: 'Pretendard', sans-serif; }
    @media screen and (max-width: 768px) { .fixed-music-widget { display: none !important; } }
    .toggle-minimize { position: absolute; top: 12px; right: 15px; width: 20px; height: 20px; background: none; color: #ccc; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 10001; font-size: 0.8rem; transition: color 0.2s; }
    .toggle-minimize:hover { color: #222; }
    .widget-container { width: 210px; height: 260px; background: #ffffff; border-radius: 26px; padding: 18px 15px 15px; box-shadow: 0 12px 40px rgba(0,0,0,0.12); display: flex; flex-direction: column; align-items: center; justify-content: space-between; overflow: hidden; position: relative; transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
    .fixed-music-widget.minimized .widget-container { height: 45px; padding-bottom: 0; }
    .fixed-music-widget.minimized .image-rotation-wrapper, .fixed-music-widget.minimized .track-meta, .fixed-music-widget.minimized .player-bottom { display: none; }
    .image-rotation-wrapper { width: 110px; height: 110px; flex-shrink: 0; cursor: pointer; position: relative; margin-top: 5px; }
    .rotated-image-area { width: 100%; height: 100%; border-radius: 50% !important; overflow: hidden; border: 2px solid #f0f0f0; box-shadow: 0 8px 20px rgba(0,0,0,0.15); animation: rotate-img 15s linear infinite; animation-play-state: paused; }
    .rotated-image-area img { width: 100%; height: 100%; object-fit: cover !important; }
    @keyframes rotate-img { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    .track-meta { text-align: center; width: 100%; margin: 8px 0 5px; }
    #meta-name { font-size: 0.85rem; font-weight: 700; color: #222; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    #meta-user { font-size: 0.7rem; color: #bbb; margin-top: 2px; }
    .player-bottom { width: 100%; }
    .nav-btns { display: flex; align-items: center; justify-content: center; gap: 14px; margin-bottom: 12px; }
    .nav-btns button { background: none; border: none; font-size: 1.05rem; cursor: pointer; color: #444; padding: 0;}
    .mini-play { width: 38px; height: 38px; border-radius: 50% !important; background: #222 !important; color: #fff !important; font-size: 0.85rem !important; display: flex; align-items: center; justify-content: center; padding: 0; box-shadow: 0 4px 10px rgba(0,0,0,0.15); }
    .control-row-final { display: flex; align-items: center; gap: 8px; background: #f7f7f7; padding: 6px 10px; border-radius: 20px; }
    .v-icon { font-size: 0.75rem; color: #bbb; }
    .vol-line { flex: 1; display: flex; align-items: center; }
    #vol-range { -webkit-appearance: none; width: 100%; height: 3px; background: #ddd; border-radius: 2px; outline: none; cursor: pointer; }
    #vol-range::-webkit-slider-thumb { -webkit-appearance: none; width: 10px; height: 10px; background: #333; border-radius: 50%; cursor: pointer; }
    #loop-btn-final { background: none; border: none; cursor: pointer; font-size: 0.8rem; color: #999; padding: 0; margin-left: 2px; display: flex; align-items: center; transition: 0.2s; }
    #loop-btn-final.active { color: #000; font-weight: 900; }
    .list-panel-style { position: absolute; bottom: -100%; left: 0; width: 100%; height: 85%; background: rgba(255,255,255,0.98); backdrop-filter: blur(12px); transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); border-top: 1px solid #eee; z-index: 10; border-top-left-radius: 24px; border-top-right-radius: 24px; }
    .list-panel-style.open { bottom: 0; }
    .list-header { padding: 12px; font-weight: bold; font-size: 0.8rem; text-align: center; border-bottom: 1px solid #f0f0f0; cursor: pointer; color: #222; }
    #list-render-target { list-style: none; padding: 0; margin: 0; max-height: 170px; overflow-y: auto; text-align: left;}
    #list-render-target li { padding: 11px 18px; font-size: 0.75rem; border-bottom: 1px solid #f9f9f9; cursor: pointer; color: #555; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;}
</style>

<script>
    const songs = [
        // โœ… jsDelivr ํ˜•์‹: https://cdn.jsdelivr.net/gh/์œ ์ €๋ช…/์ €์žฅ์†Œ๋ช…@main/ํŒŒ์ผ๋ช….mp3
        { title: "ใ‚ญใƒฅใƒผใƒ†ใ‚ฃใƒผใƒใƒ‹ใƒผ", artist: "ๅ€–็”ฐไพ†ๆœช", url: "https://cdn.jsdelivr.net/gh/khsunn50-droid/user2bi@main/%E3%82%AD%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%BC%E3%83%8F%E3%83%8B%E3%83%BC%204.mp3" }
    ];

    let current = 0;
    let isLooping = false;

    // โœ… ์ˆ˜์ • 1: new Audio() ๊ด„ํ˜ธ ๋น„์›€
    const player = new Audio();
    player.volume = 0.2;

    // โœ… ์ˆ˜์ • 2: toggleMinimize ์•„์ด์ฝ˜ ๊ต์ฒด ๋ฒ„๊ทธ ์ˆ˜์ •
    function toggleMinimize() {
        const root = document.getElementById('music-widget-root');
        const icon = document.getElementById('min-icon');
        root.classList.toggle('minimized');
        if (root.classList.contains('minimized')) {
            icon.classList.remove('fa-minus');
            icon.classList.add('fa-plus');
        } else {
            icon.classList.remove('fa-plus');
            icon.classList.add('fa-minus');
        }
    }

    function saveState() {
        localStorage.setItem('tistory_music_final_state', JSON.stringify({
            index: current, time: player.currentTime, paused: player.paused, volume: player.volume, loop: isLooping
        }));
    }

    function loadState() {
        const saved = localStorage.getItem('tistory_music_final_state');
        if (saved) {
            const state = JSON.parse(saved);
            current = state.index;
            isLooping = state.loop;
            player.volume = state.volume !== undefined ? state.volume : 0.2;
            document.getElementById('vol-range').value = player.volume;
            if (isLooping) document.getElementById('loop-btn-final').classList.add('active');
            player.loop = isLooping;
            loadTrack(current);
            player.currentTime = state.time || 0;
            if (!state.paused) {
                player.play().then(() => updateUI(true)).catch(() => updateUI(false));
            }
        } else {
            document.getElementById('meta-name').innerText = "Nothing Now";
            document.getElementById('meta-user').innerText = "Select a song";
            document.getElementById('vol-range').value = 0.2;
            if (songs.length > 0) player.src = songs[0].url;
            renderList();
        }
    }

    function loadTrack(idx) {
        if (!songs[idx]) return;
        player.src = songs[idx].url;
        document.getElementById('meta-name').innerText = songs[idx].title;
        document.getElementById('meta-user').innerText = songs[idx].artist;
        renderList();
    }

    // โœ… ์ˆ˜์ • 3: updateUI - ์ด๋ฏธ์ง€ ํšŒ์ „์„ style ๋Œ€์‹  class๋กœ ์ œ์–ดํ•ด์„œ ๋” ์•ˆ์ •์ ์œผ๋กœ
    function updateUI(isPlaying) {
        const img = document.getElementById('image-main');
        const btn = document.getElementById('main-play-btn');
        if (isPlaying) {
            btn.innerHTML = '<i class="fa-solid fa-pause"></i>';
            img.style.animationPlayState = "running";
        } else {
            btn.innerHTML = '<i class="fa-solid fa-play"></i>';
            img.style.animationPlayState = "paused";
        }
    }

    function handleToggle() {
        if (player.paused) {
            if (document.getElementById('meta-name').innerText === "Nothing Now") {
                loadTrack(current);
            }
            player.play().then(() => updateUI(true)).catch(() => updateUI(false));
        } else {
            player.pause();
            updateUI(false);
        }
        saveState();
    }

    function playPrev() { current = (current - 1 + songs.length) % songs.length; syncPlayer(); }
    function playNext() { current = (current + 1) % songs.length; syncPlayer(); }

    function syncPlayer() {
        loadTrack(current);
        player.play().then(() => updateUI(true)).catch(() => updateUI(false));
        saveState();
    }

    function changeVol() { player.volume = document.getElementById('vol-range').value; saveState(); }

    function handleLoop() {
        isLooping = !isLooping;
        player.loop = isLooping;
        document.getElementById('loop-btn-final').classList.toggle('active');
        saveState();
    }

    function togglePlaylist() { document.getElementById('list-panel').classList.toggle('open'); }

    function renderList() {
        const box = document.getElementById('list-render-target');
        box.innerHTML = "";
        songs.forEach((s, i) => {
            const li = document.createElement('li');
            li.innerText = s.title;
            li.style.color = (i === current && document.getElementById('meta-name').innerText !== "Nothing Now") ? "#000" : "#666";
            li.style.fontWeight = (i === current && document.getElementById('meta-name').innerText !== "Nothing Now") ? "700" : "400";
            li.onclick = (e) => { e.stopPropagation(); current = i; syncPlayer(); togglePlaylist(); };
            box.appendChild(li);
        });
    }

    player.onended = () => { if (!isLooping) playNext(); };
    player.ontimeupdate = saveState;
    window.addEventListener('load', loadState);
</script>

 

์ฝ”๋“œ๋Š” </body> ๋ฐ”๋กœ ์œ„์— ๋„ฃ์œผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!!

 

- ์Œ์•… ํ”Œ๋ ˆ์ด์–ด (์œˆ๋„์šฐ ์ฐฝ ๋””์ž์ธ)

PC ์ตœ์ ํ™”๋ผ ๋ชจ๋ฐ”์ผ์—์„  ๋‚˜์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค!
+ ๋“œ๋ž˜๊ทธ ๊ธฐ๋Šฅ ( x๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Œ )

 

 

    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

<div id="music-draggable-win" class="win-popup-music">
    <div id="music-header" class="win-header-music">
        <span class="win-title-music">Music_Player.exe</span>
        <div class="win-buttons-music">
            <span class="win-btn-music" onclick="toggleMusicFold()">_</span>
            <span class="win-btn-music win-btn-deco">×</span>
        </div>
    </div>

    <div id="music-body-content" class="win-body-music">
        <div class="win-img-box-music" onclick="togglePlaylist()">
            <div class="disc-wrapper">
                <img id="music-disc-img" src="https://i.postimg.cc/G2kfMW3m/e268dbe585e662e072cc592c71da11fe.png" alt="Album Art">
            </div>
        </div>

        <div class="win-text-music">
            <h3 id="meta-name">Loading...</h3>
            <p id="meta-user">Artist Info</p>
        </div>

        <div class="win-controls-music">
            <div class="btn-group-music">
                <button class="win-push-btn-music" onclick="playPrev()"><i class="fa-solid fa-backward"></i></button>
                <button id="main-play-btn" class="win-push-btn-music play-main" onclick="handleToggle()"><i class="fa-solid fa-play"></i></button>
                <button class="win-push-btn-music" onclick="playNext()"><i class="fa-solid fa-forward"></i></button>
            </div>

            <div class="win-vol-box-music">
                <button id="loop-btn-final" class="win-push-btn-music loop-btn" onclick="handleLoop()" title="๋ฐ˜๋ณต ์žฌ์ƒ">
                    <i class="fa-solid fa-repeat"></i>
                </button>
                <span style="font-size:9px; font-weight:bold; margin-left:2px; color:#333;">VOL</span>
                <div class="vol-track-bg">
                    <input type="range" id="vol-range" min="0" max="1" step="0.01" value="0.4" oninput="changeVol()">
                </div>
            </div>
        </div>

        <div id="list-panel" class="win-list-container-music">
            <div class="list-title-music" onclick="togglePlaylist()">-- PLAYLIST --</div>
            <ul id="list-render-target"></ul>
        </div>
    </div>
</div>

<style>
    .win-popup-music {
        position: fixed; top: 20px; right: 20px; width: 220px; z-index: 10001;
        background: #c0c0c0; border: 2px solid; border-color: #ffffff #808080 #808080 #ffffff;
        box-shadow: 4px 4px 10px rgba(0,0,0,0.3); font-family: 'Tahoma', sans-serif; padding: 2px;
    }
    .win-header-music {
        background: linear-gradient(90deg, #000080, #1084d0); padding: 4px 8px;
        display: flex; justify-content: space-between; align-items: center; cursor: move;
    }
    .win-title-music { color: white; font-size: 11px; font-weight: bold; pointer-events: none; }
    .win-btn-music {
        width: 18px; height: 16px; background: #c0c0c0; border: 1px solid;
        border-color: #ffffff #808080 #808080 #ffffff; font-size: 12px;
        text-align: center; line-height: 12px; cursor: pointer; margin-left: 2px; color: #000;
    }
    .win-btn-deco { cursor: default; }
    .win-body-music { padding: 12px; border: 1px inset #ffffff; margin-top: 2px; background: #c0c0c0; position: relative; overflow: hidden; }
    .folded-music { display: none !important; }
    .win-img-box-music { cursor: pointer; margin-bottom: 10px; }
    .disc-wrapper { 
        width: 100px; height: 100px; margin: 0 auto; border-radius: 50%; 
        border: 2px inset #808080; overflow: hidden;
        animation: rotate-disc 15s linear infinite; animation-play-state: paused;
    }
    .disc-wrapper img { width: 100%; height: 100%; object-fit: cover; }
    @keyframes rotate-disc { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
    .win-text-music { text-align: center; margin-bottom: 10px; }
    .win-text-music h3 { font-size: 13px; margin: 0; color: #000; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .win-text-music p { font-size: 11px; margin: 3px 0 0; color: #444; }
    .win-controls-music { display: flex; flex-direction: column; gap: 8px; }
    .btn-group-music { display: flex; justify-content: center; gap: 4px; }
    .win-push-btn-music {
        background: #c0c0c0; border: 2px solid; border-color: #ffffff #808080 #808080 #ffffff;
        cursor: pointer; padding: 3px 6px; font-size: 10px; display: flex; align-items: center; justify-content: center;
    }
    .win-push-btn-music:active { border-color: #808080 #ffffff #ffffff #808080; }
    .play-main { width: 35px; }
    .win-vol-box-music { 
        display: flex; align-items: center; gap: 5px; background: #b0b0b0; 
        padding: 4px 6px; border: 1px inset #ffffff; 
    }
    .vol-track-bg {
        flex: 1; height: 14px; background: #ffffff;
        border: 1px inset #808080; display: flex; align-items: center; padding: 0 3px;
    }
    #vol-range { 
        width: 100%; height: 4px; cursor: pointer; accent-color: #000080; 
        -webkit-appearance: none; background: transparent;
    }
    #vol-range::-webkit-slider-thumb { -webkit-appearance: none; height: 10px; width: 6px; background: #c0c0c0; border: 1px solid #000; cursor: pointer; }
    .loop-btn.active { background: #e0e0e0; border-color: #808080 #ffffff #ffffff #808080; color: #000080; }
    .win-list-container-music {
        position: absolute; bottom: -100%; left: 0; width: 100%; height: 100%;
        background: #c0c0c0; border-top: 2px solid #808080; transition: bottom 0.3s; z-index: 10;
        display: flex; flex-direction: column;
    }
    .win-list-container-music.open { bottom: 0; }
    .list-title-music { background: #808080; color: #fff; font-size: 10px; padding: 4px; text-align: center; cursor: pointer; }
    #list-render-target { list-style: none; padding: 0; margin: 5px; overflow-y: auto; flex: 1; background: #fff; border: 1px inset #808080; }
    #list-render-target li { padding: 5px 8px; font-size: 11px; border-bottom: 1px dotted #ccc; cursor: pointer; color: #333; }
    #list-render-target li:hover { background: #000080; color: #fff; }
    @media (max-width: 768px) { .win-popup-music { display: none !important; } }
</style>

<script>
    // ๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด์šฉ ์„ค์ • (๋…ธ๋ž˜ ์ถ”๊ฐ€๋จ)
    const musicSongs = [
        { title: "ใ‚ญใƒฅใƒผใƒ†ใ‚ฃใƒผใƒใƒ‹ใƒผ", artist: "ๅ€–็”ฐไพ†ๆœช", url: "https://github.com/khsunn50-droid/user2bi/raw/refs/heads/main/%E3%82%AD%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%BC%E3%83%8F%E3%83%8B%E3%83%BC%204.mp3" }
    ];

    let musicCurrent = 0;
    let musicIsLooping = false;
    const musicPlayer = new Audio();
    musicPlayer.volume = 0.4;

    const musicWin = document.getElementById("music-draggable-win");
    const musicHeader = document.getElementById("music-header");
    let musicIsDragging = false;
    let musicOffset = { x: 0, y: 0 };

    // ๋“œ๋ž˜๊ทธ ๋กœ์ง
    musicHeader.addEventListener("mousedown", (e) => {
        musicIsDragging = true;
        musicOffset.x = e.clientX - musicWin.offsetLeft;
        musicOffset.y = e.clientY - musicWin.offsetTop;
    });
    document.addEventListener("mousemove", (e) => {
        if (!musicIsDragging) return;
        musicWin.style.left = (e.clientX - musicOffset.x) + "px";
        musicWin.style.top = (e.clientY - musicOffset.y) + "px";
    });
    document.addEventListener("mouseup", () => { musicIsDragging = false; });

    // ๊ธฐ๋ณธ ๊ธฐ๋Šฅ ํ•จ์ˆ˜๋“ค
    function toggleMusicFold() { document.getElementById("music-body-content").classList.toggle("folded-music"); }
    function togglePlaylist() { document.getElementById('list-panel').classList.toggle('open'); }

    function loadMusicTrack(idx) {
        if (!musicSongs[idx]) return;
        musicPlayer.src = musicSongs[idx].url;
        document.getElementById('meta-name').innerText = musicSongs[idx].title;
        document.getElementById('meta-user').innerText = musicSongs[idx].artist;
        renderMusicList();
    }

    function updateMusicUI(isPlaying) {
        const disc = document.querySelector('.disc-wrapper');
        const btn = document.getElementById('main-play-btn');
        if (isPlaying) {
            btn.innerHTML = '<i class="fa-solid fa-pause"></i>';
            disc.style.animationPlayState = "running";
        } else {
            btn.innerHTML = '<i class="fa-solid fa-play"></i>';
            disc.style.animationPlayState = "paused";
        }
    }

    function handleToggle() {
        if (musicPlayer.paused) { musicPlayer.play(); updateMusicUI(true); } 
        else { musicPlayer.pause(); updateMusicUI(false); }
        saveMusicState();
    }

    function playPrev() { musicCurrent = (musicCurrent - 1 + musicSongs.length) % musicSongs.length; syncMusicPlayer(); }
    function playNext() { musicCurrent = (musicCurrent + 1) % musicSongs.length; syncMusicPlayer(); }
    function syncMusicPlayer() { loadMusicTrack(musicCurrent); musicPlayer.play(); updateMusicUI(true); saveMusicState(); }
    function changeVol() { musicPlayer.volume = document.getElementById('vol-range').value; saveMusicState(); }
    function handleLoop() {
        musicIsLooping = !musicIsLooping; musicPlayer.loop = musicIsLooping;
        document.getElementById('loop-btn-final').classList.toggle('active');
        saveMusicState();
    }

    function renderMusicList() {
        const box = document.getElementById('list-render-target');
        box.innerHTML = "";
        musicSongs.forEach((s, i) => {
            const li = document.createElement('li');
            li.innerText = s.title;
            if(i === musicCurrent) { li.style.background = "#000080"; li.style.color = "#fff"; }
            li.onclick = (e) => { e.stopPropagation(); musicCurrent = i; syncMusicPlayer(); togglePlaylist(); };
            box.appendChild(li);
        });
    }

    // ๐Ÿ”ฅ ์‹ค์‹œ๊ฐ„ ์ƒํƒœ ์ €์žฅ (ํŽ˜์ด์ง€ ์ด๋™ ๋Œ€์‘)
    musicPlayer.ontimeupdate = () => { saveMusicState(); };

    function saveMusicState() {
        localStorage.setItem('win95_music_state_v2', JSON.stringify({
            index: musicCurrent,
            time: musicPlayer.currentTime,
            paused: musicPlayer.paused,
            volume: musicPlayer.volume,
            loop: musicIsLooping
        }));
    }

    // ๐Ÿ”ฅ ๋กœ๋“œ ์‹œ ์ด์–ด๋“ฃ๊ธฐ ์‹คํ–‰
    window.addEventListener('load', () => {
        const saved = localStorage.getItem('win95_music_state_v2');
        if (saved) {
            const state = JSON.parse(saved);
            musicCurrent = state.index;
            musicIsLooping = state.loop;
            musicPlayer.volume = state.volume !== undefined ? state.volume : 0.4;
            document.getElementById('vol-range').value = musicPlayer.volume;
            
            if (musicIsLooping) document.getElementById('loop-btn-final').classList.add('active');
            musicPlayer.loop = musicIsLooping;

            loadMusicTrack(musicCurrent);
            
            // ์ €์žฅ๋œ ์‹œ๊ฐ„ ์ง€์ ์œผ๋กœ ์ด๋™
            if (state.time) musicPlayer.currentTime = state.time;

            // ์ด์ „ ์ƒํƒœ๊ฐ€ ์žฌ์ƒ ์ค‘์ด์—ˆ๋‹ค๋ฉด ์ž๋™ ์žฌ์ƒ ์‹œ๋„
            if (!state.paused) {
                musicPlayer.play().then(() => updateMusicUI(true)).catch(() => updateMusicUI(false));
            }
        } else {
            loadMusicTrack(musicCurrent);
        }
    });

    musicPlayer.onended = () => { if(!musicIsLooping) playNext(); };
</script>

 

- ์ปค์Šคํ…€ ์„ค๋ช…๋ฌธ

๋”๋ณด๊ธฐ

1. ์Œ์•… ์ถ”๊ฐ€ํ•˜๊ธฐ

๊ธฐ์กด ๋งˆ์ง€๋ง‰ ์ฝ”๋“œ ๋์— ์‰ผํ‘œ(,)๋ฅผ ์ฐ์–ด ์—ฐ๊ฒฐ ๊ณ ๋ฆฌ๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ๋’ค์— ์ƒˆ ์ฝ”๋“œ๋ฅผ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”.

 

*์˜ˆ์‹œ

const musicSongs = [
    { title: "๋…ธ๋ž˜1", artist: "๊ฐ€์ˆ˜1", url: "๋งํฌ1" }, // ← ์›๋ž˜ ์—†์—ˆ๋‹ค๋ฉด ์‰ผํ‘œ๋ฅผ ์ฐ์–ด์ฃผ์„ธ์š”
    { title: "๋…ธ๋ž˜2", artist: "๊ฐ€์ˆ˜2", url: "๋งํฌ2" }  // ← ์ƒˆ๋กœ ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ (์‰ผํ‘œ X)
];

 

2. ์Œ์•… ์ œ๊ฑฐํ•˜๊ธฐ

์ง€์šฐ๊ณ  ์‹ถ์€ { ... } ๋ฉ์–ด๋ฆฌ๋ฅผ ํ†ต์งธ๋กœ ์‚ญ์ œํ•˜์„ธ์š”.
์ง€์šฐ๊ณ  ๋‚œ ๋’ค, ๋‚จ์•„์žˆ๋Š” ๋งˆ์ง€๋ง‰ ์ฝ”๋“œ ๋’ค์— ์‰ผํ‘œ(,)๊ฐ€ ๋ถ™์–ด์žˆ๋‹ค๋ฉด ๊ทธ๊ฒƒ๋„ ๊ฐ™์ด ์ง€์›Œ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

*์Œ์•…์€ ๊นƒํ—ˆ๋ธŒ์— ์—…๋กœ๋“œํ•ด์„œ ์Œ์•… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌ, ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ–ˆ์Šต๋‹ˆ๋‹ค!*
(youtube ๋งํฌ๋Š” ๋˜๋Š”์ง€ ์•ˆ ๋˜๋Š”์ง€ ๋ชจ๋ฆ…๋‹ˆ๋‹ค... ๋˜๋„๋ก์ด๋ฉด ๊นƒํ—ˆ๋ธŒ์— ์—…๋กœ๋“œํ•ด์„œ ์“ฐ๋Š” ๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค!)

3. ๊นƒํ—ˆ๋ธŒ์— ์Œ์•… ์—…๋กœ๋“œ ๋ฐฉ๋ฒ•


- ๊นƒํ—ˆ๋ธŒ ๊ฒ€์ƒ‰ > ํšŒ์›๊ฐ€์ž… > ๊นƒํ—ˆ๋ธŒ ํ™ˆ์—์„œ new ํด๋ฆญ 

Repository name (์ €์žฅ์†Œ ์ด๋ฆ„)
Description (์„ค๋ช…)

๋งจ ์•„๋ž˜ ์ดˆ๋ก ๋ฒ„ํŠผ ํด๋ฆญ

๋‹ค์‹œ ํ™ˆ์œผ๋กœ ๊ฐ€์„œ ์™ผ์ชฝ์— ์ƒ์„ฑ๋œ ์ €์žฅ์†Œ ํด๋ฆญ

 uploading an existing file ํด๋ฆญ ํ›„ mp3 ํŒŒ์ผ ์—…๋กœ๋“œ > ๋งจ ์•„๋ž˜ ์ดˆ๋ก ๋ฒ„ํŠผ ํด๋ฆญ

Raw ๋ฒ„ํŠผ ์˜ค๋ฅธ์ชฝ ํด๋ฆญ ํ›„ ๋งํฌ ์ฃผ์†Œ ๋ณต์‚ฌ
์œ„ ์ฝ”๋“œ url : " " ์•ˆ์— ๋งํฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ›„,

 

https://github.com/์œ ์ €๋ช…/์ €์žฅ์†Œ๋ช…/raw/main/ํŒŒ์ผ๋ช….mp3

์œ„์˜ ์ฃผ์†Œ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•˜์‹œ๋ฉด ๋!

https://cdn.jsdelivr.net/gh/์œ ์ €๋ช…/์ €์žฅ์†Œ๋ช…@main/ํŒŒ์ผ๋ช….mp3

 

(์ด๋ ‡๊ฒŒ ํ•˜๋Š” ์ด์œ ๋Š” ๋ณด์•ˆ ์ •์ฑ… ๋•Œ๋ฌธ์— ์Œ์•… ์žฌ์ƒ์ด ๋ง‰ํž ์ˆ˜ ์žˆ์–ด์„œ)

๋”๋ณด๊ธฐ

1. ์ด๋ฏธ์ง€ ๋ณ€๊ฒฝ

<img id="music-disc-img" src="https://i.postimg.cc/0N1L1YWy/images.jpg" alt="Album Art">

 

์œ„์˜ ์ฝ”๋“œ์—์„œ src="https://~~.png ๋˜๋Š” jpg" << ๋นจ๊ฐ„์ƒ‰ ๋ถ€๋ถ„์— ์žˆ๋Š” ์ด๋ฏธ์ง€ ๋งํฌ๋ฅผ ๋ณ€๊ฒฝํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

 

๊น”๋”ํ•œ ๋””์ž์ธ์—์„œ๋Š” ์—ฌ๊ธฐ์„œ ๋ณ€๊ฒฝํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค!

<img src="https://i.postimg.cc/0N1L1YWy/images.jpg" alt="Fixed Cover">

 

 

๋ฌด๋ฃŒ ์ด๋ฏธ์ง€ ํ˜ธ์ŠคํŒ… ์‚ฌ์ดํŠธ

 

- ๊ธฐ๋ณธ ๋ณผ๋ฅจ ๋ณ€๊ฒฝ

๋”๋ณด๊ธฐ
<input type="range" id="vol-range" min="0" max="1" step="0.01" value="0.1" oninput="changeVol()">

1. ์Šฌ๋ผ์ด๋” ์œ„์น˜ ๋ณ€๊ฒฝ

์ฝ”๋“œ ์ค‘๊ฐ„์ฏค์— ์žˆ๋Š” input ํƒœ๊ทธ์˜ value ๊ฐ’์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

const musicPlayer = new Audio();
musicPlayer.volume = 0.1; // ์ด ์ˆซ์ž๋ฅผ ์œ„์™€ ๋™์ผํ•˜๊ฒŒ ๋ณ€๊ฒฝ

2. ์‹ค์ œ ์˜ค๋””์˜ค ๊ฐ’

<script> ์‹œ์ž‘ ๋ถ€๋ถ„ ๊ทผ์ฒ˜์— ์žˆ๋Š” ์„ค์ •๊ฐ’์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค. (๊น”๋”ํ•œ ๋””์ž์ธ์€ "const player")

// ์ €์žฅ๋œ ๊ฐ’์ด ์—†์„ ๋•Œ ์‚ฌ์šฉํ•  ๊ธฐ๋ณธ๊ฐ’์ž…๋‹ˆ๋‹ค.
musicPlayer.volume = state.volume !== undefined ? state.volume : 0.1; 
// ๋งˆ์ง€๋ง‰์˜ 0.1์„ ์›ํ•˜๋Š” ์ˆซ์ž๋กœ ๋ณ€๊ฒฝ

3. ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ๋ฐ์ดํ„ฐ ๋ณต๊ตฌ ๋กœ์ง (์ด์–ด๋“ฃ๊ธฐ ๋ฐฉ์ง€)

์ฝ”๋“œ ๋งจ ์•„๋ž˜์ชฝ window.addEventListener('load', ...) ๋ถ€๋ถ„์— ์žˆ๋Š” ๊ธฐ๋ณธ๊ฐ’์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

(๊น”๋”ํ•œ ๋””์ž์ธ์€ player.volume)

 

 

์ˆซ์ž๋Š” 0.0(๋ฌด์Œ)๋ถ€ํ„ฐ 1.0(์ตœ๋Œ€ ์Œ๋Ÿ‰) ์‚ฌ์ด๋กœ ์ž…๋ ฅํ•˜์‹œ๋ฉด ๋˜๋ฉฐ, ์˜ˆ๋ฅผ ๋“ค์–ด 20%๋กœ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด 0.2๋ฅผ ๋„ฃ์œผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

 

์„ธ ๊ตฐ๋ฐ ์ค‘ ํ•œ ๊ณณ์ด๋ผ๋„ ์ˆซ์ž๊ฐ€ ๋‹ค๋ฅด๋ฉด, ์ƒˆ๋กœ๊ณ ์นจํ–ˆ์„ ๋•Œ ๊ฐ‘์ž๊ธฐ ์†Œ๋ฆฌ๊ฐ€ ์ปค์ง€๊ฑฐ๋‚˜ ์Šฌ๋ผ์ด๋” ๋ฐ” ์œ„์น˜๊ฐ€ ์–ด์ƒ‰ํ•ด์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ผญ ์„ธ ๊ณณ ๋ชจ๋‘ ๋ฐ”๊ฟ”์ฃผ์„ธ์š”.

 
 
 
ํŽธํ•˜๊ฒŒ ์‚ฌ์šฉํ•ด์ฃผ์„ธ์š”!
 
๋งŒ์•ฝ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋‹ค๋ฉด ๋Œ“๊ธ€๋กœ ๋ฌธ์˜ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~ 

 

user-img 1942
1942
ํ˜„์žฌ๊ธ€
๋ฎค์ง ํ”Œ๋ ˆ์ด์–ด 2