├── .gitattributes ├── logo.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── common ├── src │ ├── common │ │ ├── resources │ │ │ ├── logo.png │ │ │ ├── pack.mcmeta │ │ │ └── assets │ │ │ │ └── musicplayer │ │ │ │ ├── textures │ │ │ │ └── gui │ │ │ │ │ ├── socialmedia │ │ │ │ │ ├── info.txt │ │ │ │ │ ├── youtube-logo.png │ │ │ │ │ └── soundcloud-logo.png │ │ │ │ │ ├── add.png │ │ │ │ │ ├── up.png │ │ │ │ │ ├── back.png │ │ │ │ │ ├── clear.png │ │ │ │ │ ├── create.png │ │ │ │ │ ├── down.png │ │ │ │ │ ├── open.png │ │ │ │ │ ├── pause.png │ │ │ │ │ ├── play.png │ │ │ │ │ ├── repeat.png │ │ │ │ │ ├── stop.png │ │ │ │ │ ├── settings.png │ │ │ │ │ ├── shuffle.png │ │ │ │ │ ├── skip-back.png │ │ │ │ │ ├── repeat-single.png │ │ │ │ │ └── skip-forward.png │ │ │ │ └── lang │ │ │ │ ├── zh_tw.json │ │ │ │ ├── zh_cn.json │ │ │ │ ├── ko_kr.json │ │ │ │ ├── ja_jp.json │ │ │ │ ├── tr_tr.json │ │ │ │ ├── ru_ru.json │ │ │ │ └── pt_br.json │ │ └── java │ │ │ └── info │ │ │ └── u_team │ │ │ └── music_player │ │ │ ├── MusicPlayerReference.java │ │ │ ├── musicplayer │ │ │ ├── IGsonLoadable.java │ │ │ ├── playlist │ │ │ │ ├── Skip.java │ │ │ │ ├── Playlists.java │ │ │ │ └── LoadedTracks.java │ │ │ ├── settings │ │ │ │ ├── Repeat.java │ │ │ │ ├── IngameOverlayPosition.java │ │ │ │ └── Settings.java │ │ │ ├── MusicPlayerFiles.java │ │ │ ├── MusicPlayerUtils.java │ │ │ ├── SettingsManager.java │ │ │ ├── PlaylistManager.java │ │ │ └── MusicPlayerManager.java │ │ │ ├── gui │ │ │ ├── BetterScreen.java │ │ │ ├── playlist │ │ │ │ ├── search │ │ │ │ │ ├── GuiMusicSearchList.java │ │ │ │ │ ├── SearchProvider.java │ │ │ │ │ ├── GuiMusicSearchListEntry.java │ │ │ │ │ ├── GuiMusicSearchListEntryMusicTrack.java │ │ │ │ │ └── GuiMusicSearchListEntryPlaylist.java │ │ │ │ ├── GuiMusicPlaylistListEntryLoading.java │ │ │ │ ├── GuiMusicPlaylistListEntry.java │ │ │ │ ├── GuiMusicPlaylistListEntryError.java │ │ │ │ ├── GuiMusicPlaylistListEntryMusicTrack.java │ │ │ │ ├── GuiMusicPlaylistListEntryPlaylistTrack.java │ │ │ │ ├── GuiMusicPlaylistListEntryPlaylistStart.java │ │ │ │ ├── GuiMusicPlaylistListEntryFunctions.java │ │ │ │ ├── GuiMusicPlaylistList.java │ │ │ │ ├── GuiMusicPlaylist.java │ │ │ │ └── GuiMusicPlaylistListEntryPlayable.java │ │ │ ├── BetterScrollableListEntry.java │ │ │ ├── settings │ │ │ │ ├── GuiMusicPlayerSettingsMixerDeviceListEntry.java │ │ │ │ └── GuiMusicPlayerSettingsMixerDeviceList.java │ │ │ ├── GuiMusicPlayerList.java │ │ │ ├── controls │ │ │ │ ├── GuiVolumeSlider.java │ │ │ │ └── GuiMusicProgressBar.java │ │ │ ├── BetterNestedGui.java │ │ │ ├── BetterScrollableList.java │ │ │ ├── util │ │ │ │ └── GuiTrackUtils.java │ │ │ ├── GuiMusicPlayer.java │ │ │ └── GuiMusicPlayerListEntry.java │ │ │ ├── init │ │ │ ├── MusicPlayerColors.java │ │ │ ├── MusicPlayerResources.java │ │ │ └── MusicPlayerLocalization.java │ │ │ ├── util │ │ │ ├── TimeUtil.java │ │ │ └── WrappedObject.java │ │ │ ├── dependency │ │ │ ├── classloader │ │ │ │ └── DependencyClassLoader.java │ │ │ └── DependencyManager.java │ │ │ └── render │ │ │ └── RenderOverlayMusicDisplay.java │ └── common_generated │ │ └── resources │ │ ├── .cache │ │ └── 27f997e835b3c7bd4c2bb367c0172854e047248d │ │ └── assets │ │ └── musicplayer │ │ └── lang │ │ ├── en_us.json │ │ └── de_de.json └── build.gradle ├── fabric ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ └── services │ │ │ │ └── info.u_team.music_player.dependency.DependencyManager$PathLocator │ │ ├── musicplayer.accesswidener │ │ ├── musicplayer.mixins.json │ │ └── fabric.mod.json │ │ └── java │ │ └── info │ │ └── u_team │ │ └── music_player │ │ ├── musicplayer │ │ └── MusicPlayerInitManager.java │ │ ├── MusicPlayerMod.java │ │ ├── init │ │ ├── MusicPlayerClientConstruct.java │ │ └── MusicPlayerKeys.java │ │ ├── impl │ │ └── FabricPathLocator.java │ │ ├── mixin │ │ ├── KeyboardHandlerMixin.java │ │ └── GuiMixin.java │ │ └── config │ │ └── ClientConfig.java └── build.gradle ├── forge ├── src │ └── main │ │ ├── resources │ │ ├── META-INF │ │ │ ├── services │ │ │ │ └── info.u_team.music_player.dependency.DependencyManager$PathLocator │ │ │ ├── accesstransformer.cfg │ │ │ └── mods.toml │ │ └── musicplayer.mixins.json │ │ └── java │ │ └── info │ │ └── u_team │ │ └── music_player │ │ ├── MusicPlayerMod.java │ │ ├── impl │ │ └── ForgePathLocator.java │ │ ├── musicplayer │ │ └── MusicPlayerInitManager.java │ │ ├── init │ │ ├── MusicPlayerCommonConstruct.java │ │ ├── MusicPlayerClientConstruct.java │ │ └── MusicPlayerKeys.java │ │ ├── mixin │ │ └── GuiMixin.java │ │ └── config │ │ └── ClientConfig.java └── build.gradle ├── neoforge └── src │ ├── main │ ├── resources │ │ └── META-INF │ │ │ ├── services │ │ │ └── info.u_team.music_player.dependency.DependencyManager$PathLocator │ │ │ ├── accesstransformer.cfg │ │ │ └── neoforge.mods.toml │ └── java │ │ └── info │ │ └── u_team │ │ └── music_player │ │ ├── MusicPlayerMod.java │ │ ├── impl │ │ └── NeoForgePathLocator.java │ │ ├── musicplayer │ │ └── MusicPlayerInitManager.java │ │ ├── config │ │ └── ClientConfig.java │ │ └── init │ │ ├── MusicPlayerClientConstruct.java │ │ └── MusicPlayerKeys.java │ └── data │ └── java │ └── info │ └── u_team │ └── music_player │ └── data │ └── MusicPlayerDataGenerator.java ├── musicplayer-lavaplayer-api ├── build.gradle └── src │ └── main │ └── java │ └── info │ └── u_team │ └── music_player │ └── lavaplayer │ └── api │ ├── audio │ ├── IPlayingTrack.java │ ├── IAudioTrack.java │ ├── IAudioTrackInfo.java │ └── IAudioTrackList.java │ ├── output │ └── IOutputConsumer.java │ ├── search │ ├── ITrackSearch.java │ └── ISearchResult.java │ ├── queue │ ├── ITrackManager.java │ └── ITrackQueue.java │ ├── util │ └── AudioUtil.java │ └── IMusicPlayer.java ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.yml │ └── bug_report.yml ├── renovate.json └── workflows │ └── build.yml ├── .gitignore ├── musicplayer-lavaplayer ├── src │ ├── main │ │ └── java │ │ │ └── info │ │ │ └── u_team │ │ │ └── music_player │ │ │ └── lavaplayer │ │ │ ├── util │ │ │ └── ObservableValue.java │ │ │ ├── queue │ │ │ ├── TrackQueueWrapper.java │ │ │ └── TrackManager.java │ │ │ ├── impl │ │ │ ├── AudioTrackImpl.java │ │ │ ├── AudioTrackInfoImpl.java │ │ │ ├── PlayingTrackImpl.java │ │ │ └── AudioTrackListImpl.java │ │ │ ├── search │ │ │ ├── SearchResult.java │ │ │ └── TrackSearch.java │ │ │ ├── sources │ │ │ └── AudioSources.java │ │ │ └── output │ │ │ └── AudioOutput.java │ └── test_player │ │ └── java │ │ └── info │ │ └── u_team │ │ └── music_player │ │ └── lavaplayer │ │ └── testimpl │ │ └── Main.java └── build.gradle ├── settings.gradle ├── CHANGELOG.md ├── README.md └── gradlew.bat /.gitattributes: -------------------------------------------------------------------------------- 1 | gradlew text eol=lf -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/logo.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /common/src/common/resources/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/logo.png -------------------------------------------------------------------------------- /common/src/common/resources/pack.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "pack": { 3 | "description": "Music Player", 4 | "pack_format": 45 5 | } 6 | } -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/socialmedia/info.txt: -------------------------------------------------------------------------------- 1 | The logos belong to youtube llc and soundCloud limited. (trademark) -------------------------------------------------------------------------------- /fabric/src/main/resources/META-INF/services/info.u_team.music_player.dependency.DependencyManager$PathLocator: -------------------------------------------------------------------------------- 1 | info.u_team.music_player.impl.FabricPathLocator -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/services/info.u_team.music_player.dependency.DependencyManager$PathLocator: -------------------------------------------------------------------------------- 1 | info.u_team.music_player.impl.ForgePathLocator -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/services/info.u_team.music_player.dependency.DependencyManager$PathLocator: -------------------------------------------------------------------------------- 1 | info.u_team.music_player.impl.NeoForgePathLocator -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | } 4 | 5 | java { 6 | toolchain { 7 | languageVersion = JavaLanguageVersion.of(21) 8 | } 9 | } -------------------------------------------------------------------------------- /fabric/src/main/resources/musicplayer.accesswidener: -------------------------------------------------------------------------------- 1 | accessWidener v1 named 2 | 3 | accessible field net/minecraft/client/gui/components/AbstractSelectionList scrolling Z -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Discord 4 | url: https://discord.u-team.info 5 | about: Please ask questions here -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/add.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/up.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/back.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/clear.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/create.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/down.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/open.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/pause.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/play.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/repeat.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/stop.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/settings.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/shuffle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/shuffle.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/skip-back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/skip-back.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/repeat-single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/repeat-single.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/skip-forward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/skip-forward.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | *.launch 3 | .settings 4 | .metadata 5 | .classpath 6 | .project 7 | .git 8 | out 9 | *.ipr 10 | *.iws 11 | *.iml 12 | .idea 13 | build 14 | .gradle 15 | eclipse 16 | run 17 | runs 18 | libs 19 | logs -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/MusicPlayerReference.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player; 2 | 3 | public class MusicPlayerReference { 4 | 5 | public static final String MODID = "musicplayer"; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/socialmedia/youtube-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/socialmedia/youtube-logo.png -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/textures/gui/socialmedia/soundcloud-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MC-U-Team/Music-Player/HEAD/common/src/common/resources/assets/musicplayer/textures/gui/socialmedia/soundcloud-logo.png -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/audio/IPlayingTrack.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.audio; 2 | 3 | public interface IPlayingTrack extends IAudioTrack { 4 | 5 | IAudioTrack getOriginalTrack(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | #net.minecraft.client.gui.widget.list.AbstractList 2 | 3 | protected net.minecraft.client.gui.components.AbstractSelectionList f_93399_ # scrolling 4 | protected net.minecraft.client.gui.components.AbstractSelectionList m_93518_()I # getMaxScroll -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/output/IOutputConsumer.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.output; 2 | 3 | @FunctionalInterface 4 | public interface IOutputConsumer { 5 | 6 | void accept(byte[] buffer, int chunkSize); 7 | 8 | } 9 | -------------------------------------------------------------------------------- /common/src/common_generated/resources/.cache/27f997e835b3c7bd4c2bb367c0172854e047248d: -------------------------------------------------------------------------------- 1 | // 1.21.1 2025-01-10T16:58:13.415439 Languages: musicplayer 2 | 4fb9f2030f2456883591582a3076a80f0564c072 assets/musicplayer/lang/de_de.json 3 | c9dfd65c281498ad527d6403f1d9582ded9169bb assets/musicplayer/lang/en_us.json 4 | -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/accesstransformer.cfg: -------------------------------------------------------------------------------- 1 | #net.minecraft.client.gui.widget.list.AbstractList 2 | 3 | protected net.minecraft.client.gui.components.AbstractSelectionList scrolling # scrolling 4 | protected net.minecraft.client.gui.components.AbstractSelectionList getMaxScroll()I # getMaxScroll -------------------------------------------------------------------------------- /forge/src/main/resources/musicplayer.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "minVersion": "0.8", 3 | "required": true, 4 | "compatibilityLevel": "JAVA_17", 5 | "package": "info.u_team.music_player.mixin", 6 | "mixins": [], 7 | "client": [ 8 | "GuiMixin" 9 | ], 10 | "injectors": { 11 | "defaultRequire": 1 12 | } 13 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/IGsonLoadable.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import java.nio.file.Path; 4 | 5 | public interface IGsonLoadable { 6 | 7 | void setBasePath(Path path); 8 | 9 | void loadFromFile(); 10 | 11 | void writeToFile(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/search/ITrackSearch.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.search; 2 | 3 | import java.util.function.Consumer; 4 | 5 | public interface ITrackSearch { 6 | 7 | void getTracks(String uri, Consumer consumer); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/audio/IAudioTrack.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.audio; 2 | 3 | public interface IAudioTrack { 4 | 5 | IAudioTrackInfo getInfo(); 6 | 7 | long getPosition(); 8 | 9 | void setPosition(long position); 10 | 11 | long getDuration(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /fabric/src/main/resources/musicplayer.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "minVersion": "0.8", 3 | "required": true, 4 | "compatibilityLevel": "JAVA_17", 5 | "refmap": "musicplayer.mixins.refmap.json", 6 | "package": "info.u_team.music_player.mixin", 7 | "mixins": [], 8 | "client": [ 9 | "KeyboardHandlerMixin", 10 | "GuiMixin" 11 | ], 12 | "injectors": { 13 | "defaultRequire": 1 14 | } 15 | } -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/BetterScreen.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import net.minecraft.client.gui.screens.Screen; 4 | import net.minecraft.network.chat.Component; 5 | 6 | public abstract class BetterScreen extends Screen implements BetterNestedGui { 7 | 8 | public BetterScreen(Component title) { 9 | super(title); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/playlist/Skip.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.playlist; 2 | 3 | public enum Skip { 4 | 5 | FORWARD(1), 6 | PREVIOUS(-1); 7 | 8 | private final int value; 9 | 10 | private Skip(int value) { 11 | this.value = value; 12 | } 13 | 14 | public int getValue() { 15 | return value; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/audio/IAudioTrackInfo.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.audio; 2 | 3 | public interface IAudioTrackInfo { 4 | 5 | String getTitle(); 6 | 7 | String getAuthor(); 8 | 9 | String getIdentifier(); 10 | 11 | String getURI(); 12 | 13 | boolean isStream(); 14 | 15 | String getFixedTitle(); 16 | 17 | String getFixedAuthor(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/audio/IAudioTrackList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.audio; 2 | 3 | import java.util.List; 4 | 5 | public interface IAudioTrackList { 6 | 7 | String getName(); 8 | 9 | List getTracks(); 10 | 11 | IAudioTrack getSelectedTrack(); 12 | 13 | boolean isSearch(); 14 | 15 | boolean hasUri(); 16 | 17 | String getUri(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/MusicPlayerMod.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player; 2 | 3 | import info.u_team.u_team_core.util.annotation.AnnotationManager; 4 | import net.neoforged.fml.common.Mod; 5 | 6 | @Mod(MusicPlayerMod.MODID) 7 | public class MusicPlayerMod { 8 | 9 | public static final String MODID = MusicPlayerReference.MODID; 10 | 11 | public MusicPlayerMod() { 12 | AnnotationManager.callAnnotations(MODID); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:recommended", 5 | ":prHourlyLimitNone" 6 | ], 7 | "prConcurrentLimit": 0, 8 | "baseBranches": [ 9 | "1.21.1", 10 | "1.20.6", 11 | "1.20.1", 12 | "1.19.4", 13 | "1.19.2", 14 | "1.18.2", 15 | "1.16.5", 16 | "1.15.2", 17 | "1.14.4", 18 | "1.12.2", 19 | "1.8.9-backport" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/MusicPlayerMod.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player; 2 | 3 | import info.u_team.u_team_core.util.annotation.AnnotationManager; 4 | import net.minecraftforge.fml.common.Mod; 5 | 6 | @Mod(MusicPlayerMod.MODID) 7 | public class MusicPlayerMod { 8 | 9 | public static final String MODID = MusicPlayerReference.MODID; 10 | 11 | public MusicPlayerMod() { 12 | AnnotationManager.callAnnotations(MODID); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/musicplayer/MusicPlayerInitManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import info.u_team.music_player.config.ClientConfig; 4 | import info.u_team.music_player.dependency.DependencyManager; 5 | 6 | public class MusicPlayerInitManager { 7 | 8 | public static void register() { 9 | MusicPlayerManager.setup(DependencyManager.MUSICPLAYER_CLASSLOADER, ClientConfig.getInstance().internalPlaylists); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/init/MusicPlayerColors.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.u_team_core.util.RGBA; 4 | 5 | public class MusicPlayerColors { 6 | 7 | public static final RGBA GREY = new RGBA(0x555555FF); 8 | 9 | public static final RGBA GREEN = new RGBA(0x3E9100FF); 10 | 11 | public static final RGBA YELLOW = new RGBA(0xFFFF00FF); 12 | 13 | public static final RGBA LIGHT_GREEN = new RGBA(0x80FF00FF); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/queue/ITrackManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.queue; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IPlayingTrack; 4 | 5 | public interface ITrackManager { 6 | 7 | void start(); 8 | 9 | void stop(); 10 | 11 | void setTrackQueue(ITrackQueue queue); 12 | 13 | void skip(); 14 | 15 | void setPaused(boolean value); 16 | 17 | boolean isPaused(); 18 | 19 | IPlayingTrack getCurrentTrack(); 20 | } 21 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/search/GuiMusicSearchList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist.search; 2 | 3 | import info.u_team.music_player.gui.BetterScrollableList; 4 | 5 | public class GuiMusicSearchList extends BetterScrollableList { 6 | 7 | public GuiMusicSearchList() { 8 | super(0, 0, 0, 0, 40, 20); 9 | } 10 | 11 | public void clear() { 12 | clearEntries(); 13 | } 14 | 15 | public void add(GuiMusicSearchListEntry entry) { 16 | addEntry(entry); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/BetterScrollableListEntry.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import info.u_team.u_team_core.gui.elements.ScrollableListEntry; 4 | 5 | public abstract class BetterScrollableListEntry> extends ScrollableListEntry { 6 | 7 | @SuppressWarnings("unchecked") 8 | @Override 9 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 10 | getList().setSelected((T) this); 11 | return super.mouseClicked(mouseX, mouseY, button); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/search/ISearchResult.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.search; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackList; 5 | 6 | public interface ISearchResult { 7 | 8 | String getUri(); 9 | 10 | boolean isList(); 11 | 12 | IAudioTrackList getTrackList(); 13 | 14 | IAudioTrack getTrack(); 15 | 16 | boolean hasError(); 17 | 18 | String getErrorMessage(); 19 | 20 | StackTraceElement[] getStackTrace(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/MusicPlayerMod.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player; 2 | 3 | import org.slf4j.Logger; 4 | 5 | import com.mojang.logging.LogUtils; 6 | 7 | import info.u_team.music_player.init.MusicPlayerClientConstruct; 8 | import net.fabricmc.api.ClientModInitializer; 9 | 10 | public class MusicPlayerMod implements ClientModInitializer { 11 | 12 | public static final String MODID = MusicPlayerReference.MODID; 13 | public static Logger LOGGER = LogUtils.getLogger(); 14 | 15 | @Override 16 | public void onInitializeClient() { 17 | MusicPlayerClientConstruct.construct(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature request 2 | description: Propose a new feature 3 | labels: ["enhancement"] 4 | title: "[MC-Version] " 5 | 6 | body: 7 | - type: textarea 8 | id: feature_description 9 | attributes: 10 | label: Detailed description of the feature 11 | validations: 12 | required: true 13 | 14 | - type: checkboxes 15 | id: verified_feature 16 | attributes: 17 | label: Verify feature request 18 | options: 19 | - label: "I have checked that this is not a duplicate feature request and the feature does not yet exist in the latest version" 20 | required: true -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/util/TimeUtil.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.util; 2 | 3 | public class TimeUtil { 4 | 5 | private final static int MINUTES_IN_AN_HOUR = 60; 6 | private final static int SECONDS_IN_A_MINUTE = 60; 7 | 8 | public static String timeConversion(long seconds) { 9 | long minutes = seconds / SECONDS_IN_A_MINUTE; 10 | seconds -= minutes * SECONDS_IN_A_MINUTE; 11 | 12 | final long hours = minutes / MINUTES_IN_AN_HOUR; 13 | minutes -= hours * MINUTES_IN_AN_HOUR; 14 | 15 | return (hours > 0 ? (hours + ":") : "") + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/init/MusicPlayerClientConstruct.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.music_player.config.ClientConfig; 4 | import info.u_team.music_player.dependency.DependencyManager; 5 | import info.u_team.music_player.musicplayer.MusicPlayerInitManager; 6 | 7 | public class MusicPlayerClientConstruct { 8 | 9 | public static void construct() { 10 | System.setProperty("http.agent", "Chrome"); 11 | 12 | ClientConfig.load(); 13 | 14 | DependencyManager.load(); 15 | 16 | MusicPlayerInitManager.register(); 17 | MusicPlayerKeys.register(); 18 | 19 | MusicPlayerEventHandler.register(); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/impl/ForgePathLocator.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.impl; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | 6 | import info.u_team.music_player.dependency.DependencyManager.PathLocator; 7 | import net.minecraftforge.fml.ModList; 8 | import net.minecraftforge.forgespi.locating.IModFile; 9 | 10 | public class ForgePathLocator implements PathLocator { 11 | 12 | @Override 13 | public Path locate(String modid, String folder) throws IOException, IllegalStateException { 14 | final IModFile modfile = ModList.get().getModFileById(modid).getFile(); 15 | 16 | return modfile.findResource(folder); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/impl/NeoForgePathLocator.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.impl; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | 6 | import info.u_team.music_player.dependency.DependencyManager.PathLocator; 7 | import net.neoforged.fml.ModList; 8 | import net.neoforged.neoforgespi.locating.IModFile; 9 | 10 | public class NeoForgePathLocator implements PathLocator { 11 | 12 | @Override 13 | public Path locate(String modid, String folder) throws IOException, IllegalStateException { 14 | final IModFile modfile = ModList.get().getModFileById(modid).getFile(); 15 | 16 | return modfile.findResource(folder); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/musicplayer/MusicPlayerInitManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import info.u_team.music_player.config.ClientConfig; 4 | import info.u_team.music_player.dependency.DependencyManager; 5 | import net.neoforged.bus.api.IEventBus; 6 | import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; 7 | 8 | public class MusicPlayerInitManager { 9 | 10 | private static void setup(FMLClientSetupEvent event) { 11 | MusicPlayerManager.setup(DependencyManager.MUSICPLAYER_CLASSLOADER, ClientConfig.getInstance().internalPlaylists.get()); 12 | } 13 | 14 | public static void registerMod(IEventBus bus) { 15 | bus.addListener(MusicPlayerInitManager::setup); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/musicplayer/MusicPlayerInitManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import info.u_team.music_player.config.ClientConfig; 4 | import info.u_team.music_player.dependency.DependencyManager; 5 | import net.minecraftforge.eventbus.api.IEventBus; 6 | import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; 7 | 8 | public class MusicPlayerInitManager { 9 | 10 | private static void setup(FMLClientSetupEvent event) { 11 | MusicPlayerManager.setup(DependencyManager.MUSICPLAYER_CLASSLOADER, ClientConfig.getInstance().internalPlaylists.get()); 12 | } 13 | 14 | public static void registerMod(IEventBus bus) { 15 | bus.addListener(MusicPlayerInitManager::setup); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/util/AudioUtil.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import javax.sound.sampled.AudioSystem; 7 | import javax.sound.sampled.Line; 8 | import javax.sound.sampled.Mixer; 9 | 10 | public class AudioUtil { 11 | 12 | public static List findAudioDevices(Line.Info lineInfo) { 13 | final List list = new ArrayList<>(); 14 | for (final Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) { 15 | final Mixer mixer = AudioSystem.getMixer(mixerInfo); 16 | if (mixer.isLineSupported(lineInfo)) { 17 | list.add(mixerInfo.getName()); 18 | } 19 | } 20 | return list; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/impl/FabricPathLocator.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.impl; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.Path; 5 | 6 | import info.u_team.music_player.dependency.DependencyManager.PathLocator; 7 | import net.fabricmc.loader.api.FabricLoader; 8 | import net.fabricmc.loader.api.ModContainer; 9 | 10 | public class FabricPathLocator implements PathLocator { 11 | 12 | @Override 13 | public Path locate(String modid, String folder) throws IOException, IllegalStateException { 14 | final ModContainer container = FabricLoader.getInstance().getModContainer(modid).orElseThrow(IllegalStateException::new); 15 | 16 | return container.findPath(folder).orElseThrow(IllegalStateException::new); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/init/MusicPlayerCommonConstruct.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.music_player.MusicPlayerMod; 4 | import info.u_team.u_team_core.api.construct.Construct; 5 | import info.u_team.u_team_core.api.construct.ModConstruct; 6 | import net.minecraftforge.fml.IExtensionPoint.DisplayTest; 7 | import net.minecraftforge.fml.ModLoadingContext; 8 | 9 | @Construct(modid = MusicPlayerMod.MODID) 10 | public class MusicPlayerCommonConstruct implements ModConstruct { 11 | 12 | @SuppressWarnings("removal") 13 | // TODO remove later 14 | @Override 15 | public void construct() { 16 | ModLoadingContext.get().registerExtensionPoint(DisplayTest.class, () -> new DisplayTest(() -> DisplayTest.IGNORESERVERONLY, (a, b) -> true)); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/mixin/KeyboardHandlerMixin.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import info.u_team.music_player.init.MusicPlayerEventHandler; 9 | import net.minecraft.client.KeyboardHandler; 10 | 11 | @Mixin(KeyboardHandler.class) 12 | abstract class KeyboardHandlerMixin { 13 | 14 | @Inject(method = "keyPress(JIIII)V", at = @At(value = "TAIL")) 15 | private void musicplayer$keyInputAfterAllHandling(long window, int keyCode, int scanCode, int code, int modifiers, CallbackInfo info) { 16 | MusicPlayerEventHandler.onKeyInput(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/queue/ITrackQueue.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api.queue; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | 5 | public interface ITrackQueue { 6 | 7 | /** 8 | * This calculates the next {@link IAudioTrack} for this queue. This method has a side effect. 9 | * 10 | * @return true if a next track could be calculated false otherwise 11 | */ 12 | boolean calculateNext(); 13 | 14 | /** 15 | * Get the calculated {@link IAudioTrack}. This method is a getter and can only return an {@link IAudioTrack} if 16 | * {@link ITrackQueue#calculateNext()} has been called before with true as result. 17 | * 18 | * @return The calculated {@link IAudioTrack} 19 | */ 20 | IAudioTrack getNext(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [pull_request, push] 3 | 4 | jobs: 5 | build: 6 | strategy: 7 | matrix: 8 | java: [21] 9 | os: [ubuntu-latest] 10 | name: Build - Java ${{ matrix.java }} 11 | runs-on: ${{ matrix.os }} 12 | steps: 13 | - name: checkout repository 14 | uses: actions/checkout@v4 15 | - name: validate gradle wrapper 16 | uses: gradle/actions/wrapper-validation@v4 17 | - name: setup jdk ${{ matrix.java }} 18 | uses: actions/setup-java@v4 19 | with: 20 | distribution: temurin 21 | java-version: ${{ matrix.java }} 22 | cache: gradle 23 | - name: make gradle wrapper executable 24 | if: ${{ runner.os != 'Windows' }} 25 | run: chmod +x ./gradlew 26 | - name: build 27 | run: ./gradlew assemble --no-daemon -Dorg.gradle.jvmargs=-Xmx6G -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryLoading.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_PLAYLIST_LOADING; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 5 | 6 | import net.minecraft.client.gui.GuiGraphics; 7 | 8 | public class GuiMusicPlaylistListEntryLoading extends GuiMusicPlaylistListEntry { 9 | 10 | @Override 11 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 12 | final String text = getTranslation(GUI_PLAYLIST_LOADING); 13 | guiGraphics.drawString(minecraft.font, text, entryX + (entryWidth / 2) - (minecraft.font.width(text) / 2), entryY + 20, 0xFF0000, false); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/util/ObservableValue.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class ObservableValue { 7 | 8 | private T value; 9 | private final List> changeListener; 10 | 11 | public ObservableValue(T value) { 12 | this.value = value; 13 | changeListener = new ArrayList<>(); 14 | } 15 | 16 | public void registerListener(ChangeListener listener) { 17 | changeListener.add(listener); 18 | } 19 | 20 | public void setValue(T value) { 21 | this.value = value; 22 | changeListener.forEach(listener -> listener.update(value)); 23 | } 24 | 25 | public T getValue() { 26 | return value; 27 | } 28 | 29 | @FunctionalInterface 30 | public interface ChangeListener { 31 | 32 | void update(T value); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /neoforge/src/data/java/info/u_team/music_player/data/MusicPlayerDataGenerator.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.data; 2 | 3 | import info.u_team.music_player.MusicPlayerMod; 4 | import info.u_team.music_player.data.provider.MusicPlayerLanguagesProvider; 5 | import info.u_team.u_team_core.data.GenerationData; 6 | import net.neoforged.bus.api.SubscribeEvent; 7 | import net.neoforged.fml.common.EventBusSubscriber; 8 | import net.neoforged.fml.common.EventBusSubscriber.Bus; 9 | import net.neoforged.neoforge.data.event.GatherDataEvent; 10 | 11 | @EventBusSubscriber(modid = MusicPlayerMod.MODID, bus = Bus.MOD) 12 | public class MusicPlayerDataGenerator { 13 | 14 | @SubscribeEvent 15 | public static void data(GatherDataEvent event) { 16 | final GenerationData data = new GenerationData(MusicPlayerMod.MODID, event); 17 | data.addProvider(event.includeClient(), MusicPlayerLanguagesProvider::new); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/mixin/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import info.u_team.music_player.init.MusicPlayerEventHandler; 9 | import net.minecraft.client.DeltaTracker; 10 | import net.minecraft.client.gui.Gui; 11 | import net.minecraft.client.gui.GuiGraphics; 12 | 13 | @Mixin(Gui.class) 14 | abstract class GuiMixin { 15 | 16 | @Inject(method = "renderDemoOverlay(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", at = @At(value = "HEAD")) 17 | private void musicplayer$renderTextInGui(GuiGraphics guiGraphics, DeltaTracker partialTick, CallbackInfo info) { 18 | MusicPlayerEventHandler.onRenderGameOverlay(guiGraphics, partialTick); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/mixin/GuiMixin.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.mixin; 2 | 3 | import org.spongepowered.asm.mixin.Mixin; 4 | import org.spongepowered.asm.mixin.injection.At; 5 | import org.spongepowered.asm.mixin.injection.Inject; 6 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 7 | 8 | import info.u_team.music_player.init.MusicPlayerEventHandler; 9 | import net.minecraft.client.DeltaTracker; 10 | import net.minecraft.client.gui.Gui; 11 | import net.minecraft.client.gui.GuiGraphics; 12 | 13 | @Mixin(Gui.class) 14 | abstract class GuiMixin { 15 | 16 | @Inject(method = "renderDemoOverlay(Lnet/minecraft/client/gui/GuiGraphics;Lnet/minecraft/client/DeltaTracker;)V", at = @At(value = "HEAD")) 17 | private void musicplayer$renderTextInGui(GuiGraphics guiGraphics, DeltaTracker partialTick, CallbackInfo info) { 18 | MusicPlayerEventHandler.onRenderGameOverlay(guiGraphics, partialTick); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer-api/src/main/java/info/u_team/music_player/lavaplayer/api/IMusicPlayer.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.api; 2 | 3 | import javax.sound.sampled.DataLine; 4 | 5 | import info.u_team.music_player.lavaplayer.api.output.IOutputConsumer; 6 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 7 | import info.u_team.music_player.lavaplayer.api.search.ITrackSearch; 8 | 9 | public interface IMusicPlayer { 10 | 11 | ITrackManager getTrackManager(); 12 | 13 | ITrackSearch getTrackSearch(); 14 | 15 | void startAudioOutput(); 16 | 17 | void setMixer(String name); 18 | 19 | String getMixer(); 20 | 21 | DataLine.Info getSpeakerInfo(); 22 | 23 | int getVolume(); 24 | 25 | void setVolume(int volume); 26 | 27 | float getSpeed(); 28 | 29 | void setSpeed(float speed); 30 | 31 | float getPitch(); 32 | 33 | void setPitch(float pitch); 34 | 35 | void setOutputConsumer(IOutputConsumer consumer); 36 | } 37 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/search/SearchProvider.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist.search; 2 | 3 | import info.u_team.music_player.init.MusicPlayerResources; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public enum SearchProvider { 7 | 8 | YOUTUBE("ytsearch:", MusicPlayerResources.TEXTURE_SOCIAL_YOUTUBE), 9 | SOUNDCLOUD("scsearch:", MusicPlayerResources.TEXTURE_SOCIAL_SOUNDCLOUD); 10 | 11 | private final String prefix; 12 | private final ResourceLocation logo; 13 | 14 | private SearchProvider(String prefix, ResourceLocation logo) { 15 | this.prefix = prefix; 16 | this.logo = logo; 17 | } 18 | 19 | public String getPrefix() { 20 | return prefix; 21 | } 22 | 23 | public ResourceLocation getLogo() { 24 | return logo; 25 | } 26 | 27 | public static SearchProvider toggle(SearchProvider provider) { 28 | if (provider == YOUTUBE) { 29 | return SOUNDCLOUD; 30 | } 31 | return YOUTUBE; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntry.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.gui.BetterScrollableListEntry; 4 | import info.u_team.music_player.gui.util.GuiTrackUtils; 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | import net.minecraft.network.chat.CommonComponents; 8 | import net.minecraft.network.chat.Component; 9 | 10 | public abstract class GuiMusicPlaylistListEntry extends BetterScrollableListEntry { 11 | 12 | protected void addTrackInfo(GuiGraphics guiGraphics, IAudioTrack track, int entryX, int entryY, int entryWidth, int leftMargin, int titleColor) { 13 | GuiTrackUtils.addTrackInfo(guiGraphics, track, entryX, entryY, entryWidth, leftMargin, titleColor); 14 | } 15 | 16 | protected void tick() { 17 | } 18 | 19 | @Override 20 | public Component getNarration() { 21 | return CommonComponents.EMPTY; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/settings/Repeat.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.settings; 2 | 3 | import info.u_team.music_player.init.MusicPlayerResources; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public enum Repeat { 7 | 8 | NO(false, MusicPlayerResources.TEXTURE_REPEAT), 9 | PLAYLIST(true, MusicPlayerResources.TEXTURE_REPEAT), 10 | SINGLE(true, MusicPlayerResources.TEXTURE_REPEAT_SINGLE); 11 | 12 | private final boolean active; 13 | private final ResourceLocation resource; 14 | 15 | private Repeat(boolean active, ResourceLocation resource) { 16 | this.active = active; 17 | this.resource = resource; 18 | } 19 | 20 | public ResourceLocation getResource() { 21 | return resource; 22 | } 23 | 24 | public boolean isActive() { 25 | return active; 26 | } 27 | 28 | public static Repeat forwardCycle(Repeat repeat) { 29 | if (repeat == NO) { 30 | repeat = PLAYLIST; 31 | } else if (repeat == PLAYLIST) { 32 | repeat = SINGLE; 33 | } else { 34 | repeat = NO; 35 | } 36 | return repeat; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/queue/TrackQueueWrapper.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.queue; 2 | 3 | import com.sedmelluq.discord.lavaplayer.track.AudioTrack; 4 | 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.queue.ITrackQueue; 7 | import info.u_team.music_player.lavaplayer.impl.AudioTrackImpl; 8 | 9 | public class TrackQueueWrapper { 10 | 11 | private final ITrackQueue queue; 12 | 13 | public TrackQueueWrapper(ITrackQueue queue) { 14 | this.queue = queue; 15 | } 16 | 17 | public boolean calculateNext() { 18 | return queue.calculateNext(); 19 | } 20 | 21 | public AudioTrack getNext() { 22 | final IAudioTrack track = queue.getNext(); 23 | if (track == null) { 24 | return null; 25 | } else { 26 | final AudioTrack audiotrack = ((AudioTrackImpl) track).getImplTrack().makeClone(); // We know this cast must work because this interface is only implemented by AudioTrackImpl. Still not the best. 27 | audiotrack.setUserData(track); 28 | return audiotrack; 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/settings/GuiMusicPlayerSettingsMixerDeviceListEntry.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.settings; 2 | 3 | import info.u_team.music_player.gui.BetterScrollableListEntry; 4 | import net.minecraft.client.gui.GuiGraphics; 5 | import net.minecraft.network.chat.CommonComponents; 6 | import net.minecraft.network.chat.Component; 7 | 8 | class GuiMusicPlayerSettingsMixerDeviceListEntry extends BetterScrollableListEntry { 9 | 10 | private final String mixerName; 11 | 12 | public GuiMusicPlayerSettingsMixerDeviceListEntry(String mixerName) { 13 | this.mixerName = mixerName; 14 | } 15 | 16 | @Override 17 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 18 | guiGraphics.drawString(minecraft.font, mixerName, entryX + 5, entryY + 5, 0x0083FF, false); 19 | } 20 | 21 | public String getMixerName() { 22 | return mixerName; 23 | } 24 | 25 | @Override 26 | public Component getNarration() { 27 | return CommonComponents.EMPTY; 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/impl/AudioTrackImpl.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.impl; 2 | 3 | import com.sedmelluq.discord.lavaplayer.track.AudioTrack; 4 | 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackInfo; 7 | 8 | public class AudioTrackImpl implements IAudioTrack { 9 | 10 | protected final AudioTrack track; 11 | 12 | private final IAudioTrackInfo info; 13 | 14 | public AudioTrackImpl(AudioTrack track) { 15 | this.track = track; 16 | info = track.getInfo() != null ? new AudioTrackInfoImpl(track.getInfo()) : null; 17 | } 18 | 19 | @Override 20 | public IAudioTrackInfo getInfo() { 21 | return info; 22 | } 23 | 24 | @Override 25 | public long getPosition() { 26 | return track.getPosition(); 27 | } 28 | 29 | @Override 30 | public void setPosition(long position) { 31 | track.setPosition(position); 32 | } 33 | 34 | @Override 35 | public long getDuration() { 36 | return track.getDuration(); 37 | } 38 | 39 | public AudioTrack getImplTrack() { 40 | return track; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/config/ClientConfig.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.config; 2 | 3 | import org.apache.commons.lang3.tuple.Pair; 4 | 5 | import net.minecraftforge.common.ForgeConfigSpec; 6 | import net.minecraftforge.common.ForgeConfigSpec.BooleanValue; 7 | import net.minecraftforge.common.ForgeConfigSpec.Builder; 8 | 9 | public class ClientConfig { 10 | 11 | public static final ForgeConfigSpec CONFIG; 12 | private static final ClientConfig INSTANCE; 13 | 14 | static { 15 | final Pair pair = new Builder().configure(ClientConfig::new); 16 | CONFIG = pair.getRight(); 17 | INSTANCE = pair.getLeft(); 18 | } 19 | 20 | public static ClientConfig getInstance() { 21 | return INSTANCE; 22 | } 23 | 24 | public final BooleanValue internalPlaylists; 25 | 26 | private ClientConfig(Builder builder) { 27 | builder.comment("Client configuration settings").push("client"); 28 | internalPlaylists = builder.comment("Should we use instead of the global appdata dir a local dir in configs for storing and loading our playlist").worldRestart().define("internalPlaylists", false); 29 | builder.pop(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/config/ClientConfig.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.config; 2 | 3 | import org.apache.commons.lang3.tuple.Pair; 4 | 5 | import net.neoforged.neoforge.common.ModConfigSpec; 6 | import net.neoforged.neoforge.common.ModConfigSpec.BooleanValue; 7 | import net.neoforged.neoforge.common.ModConfigSpec.Builder; 8 | 9 | public class ClientConfig { 10 | 11 | public static final ModConfigSpec CONFIG; 12 | private static final ClientConfig INSTANCE; 13 | 14 | static { 15 | final Pair pair = new Builder().configure(ClientConfig::new); 16 | CONFIG = pair.getRight(); 17 | INSTANCE = pair.getLeft(); 18 | } 19 | 20 | public static ClientConfig getInstance() { 21 | return INSTANCE; 22 | } 23 | 24 | public final BooleanValue internalPlaylists; 25 | 26 | private ClientConfig(Builder builder) { 27 | builder.comment("Client configuration settings").push("client"); 28 | internalPlaylists = builder.comment("Should we use instead of the global appdata dir a local dir in configs for storing and loading our playlist").worldRestart().define("internalPlaylists", false); 29 | builder.pop(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryError.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 4 | import info.u_team.music_player.musicplayer.playlist.Playlist; 5 | import info.u_team.music_player.musicplayer.playlist.Playlists; 6 | import net.minecraft.client.gui.GuiGraphics; 7 | 8 | public class GuiMusicPlaylistListEntryError extends GuiMusicPlaylistListEntryFunctions { 9 | 10 | private final String error; 11 | 12 | public GuiMusicPlaylistListEntryError(GuiMusicPlaylistList guilist, Playlists playlists, Playlist playlist, LoadedTracks loadedTrack, String error) { 13 | super(guilist, playlists, playlist, loadedTrack, null); 14 | this.error = error; 15 | } 16 | 17 | @Override 18 | public void drawEntryExtended(GuiGraphics guiGraphics, int entryX, int entryY, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean mouseInList, float partialTicks) { 19 | guiGraphics.drawString(minecraft.font, error, entryX + 5, entryY + 5, 0xFF0000, false); 20 | guiGraphics.drawString(minecraft.font, uri.get(), entryX + 5, entryY + 25, 0xFF0000, false); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/MusicPlayerFiles.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import java.nio.file.Files; 4 | import java.nio.file.Path; 5 | import java.nio.file.Paths; 6 | 7 | import org.apache.logging.log4j.LogManager; 8 | import org.apache.logging.log4j.Logger; 9 | 10 | import net.harawata.appdirs.AppDirsFactory; 11 | import net.minecraft.client.Minecraft; 12 | 13 | public class MusicPlayerFiles { 14 | 15 | private static final Logger LOGGER = LogManager.getLogger(); 16 | 17 | private Path directory; 18 | 19 | MusicPlayerFiles() { 20 | } 21 | 22 | public void load(boolean internalPlaylists) { 23 | if (internalPlaylists) { 24 | directory = Paths.get(Minecraft.getInstance().gameDirectory.toString(), "config/musicplayer"); 25 | } else { 26 | directory = Paths.get(AppDirsFactory.getInstance().getUserConfigDir("musicplayer", null, "mc-u-team", true)); 27 | } 28 | 29 | try { 30 | Files.createDirectories(directory); 31 | } catch (final Exception ex) { 32 | LOGGER.error("Could not create music player directories", ex); 33 | } 34 | } 35 | 36 | public Path getDirectory() { 37 | return directory; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/GuiMusicPlayerList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 4 | import info.u_team.music_player.musicplayer.playlist.Playlist; 5 | import info.u_team.music_player.musicplayer.playlist.Playlists; 6 | 7 | public class GuiMusicPlayerList extends BetterScrollableList { 8 | 9 | private final Playlists playlists; 10 | 11 | public GuiMusicPlayerList(int x, int y, int width, int height) { 12 | super(x, y, width, height, 50, 20); 13 | 14 | playlists = MusicPlayerManager.getPlaylistManager().getPlaylists(); 15 | playlists.forEach(playlist -> addEntry(new GuiMusicPlayerListEntry(this, playlists, playlist))); 16 | } 17 | 18 | public void addPlaylist(String name) { 19 | final Playlist playlist = new Playlist(name); 20 | playlists.add(playlist); 21 | addEntry(new GuiMusicPlayerListEntry(this, playlists, playlist)); 22 | } 23 | 24 | public void removePlaylist(GuiMusicPlayerListEntry entry) { 25 | playlists.remove(entry.getPlaylist()); 26 | removeEntry(entry); 27 | } 28 | 29 | public Playlists getPlaylists() { 30 | return playlists; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryMusicTrack.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 5 | import info.u_team.music_player.musicplayer.playlist.Playlist; 6 | import info.u_team.music_player.musicplayer.playlist.Playlists; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | 9 | public class GuiMusicPlaylistListEntryMusicTrack extends GuiMusicPlaylistListEntryFunctions { 10 | 11 | private final IAudioTrack track; 12 | 13 | public GuiMusicPlaylistListEntryMusicTrack(GuiMusicPlaylistList guilist, Playlists playlists, Playlist playlist, LoadedTracks loadedTrack) { 14 | super(guilist, playlists, playlist, loadedTrack, loadedTrack.getTrack()); 15 | track = loadedTrack.getTrack(); 16 | } 17 | 18 | @Override 19 | public void drawEntryExtended(GuiGraphics guiGraphics, int entryX, int entryY, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean mouseInList, float partialTicks) { 20 | addTrackInfo(guiGraphics, track, entryX, entryY, entryWidth, 5, isPlaying() ? 0xe02626 : 0x419BF4); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/dependency/classloader/DependencyClassLoader.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.dependency.classloader; 2 | 3 | import java.net.URL; 4 | import java.net.URLClassLoader; 5 | import java.util.Arrays; 6 | import java.util.Collection; 7 | 8 | public class DependencyClassLoader extends URLClassLoader { 9 | 10 | private final Collection ourClassLoaderPackages = Arrays.asList("info.u_team.music_player.lavaplayer.api", "javax.script", "javax.lang", "org.slf4j"); 11 | 12 | static { 13 | ClassLoader.registerAsParallelCapable(); 14 | } 15 | 16 | private final ClassLoader ourClassLoader; 17 | 18 | public DependencyClassLoader() { 19 | super(new URL[] {}, null); 20 | ourClassLoader = getClass().getClassLoader(); 21 | } 22 | 23 | @Override 24 | public Class loadClass(String name) throws ClassNotFoundException { 25 | try { 26 | return super.loadClass(name); 27 | } catch (final ClassNotFoundException ex) { 28 | if (ourClassLoaderPackages.stream().anyMatch(name::startsWith)) { 29 | return ourClassLoader.loadClass(name); 30 | } 31 | throw ex; 32 | } 33 | } 34 | 35 | @Override 36 | public void addURL(URL url) { 37 | super.addURL(url); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/settings/GuiMusicPlayerSettingsMixerDeviceList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.settings; 2 | 3 | import info.u_team.music_player.gui.BetterScrollableList; 4 | import info.u_team.music_player.lavaplayer.api.IMusicPlayer; 5 | import info.u_team.music_player.lavaplayer.api.util.AudioUtil; 6 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 7 | 8 | public class GuiMusicPlayerSettingsMixerDeviceList extends BetterScrollableList { 9 | 10 | private final IMusicPlayer player; 11 | 12 | public GuiMusicPlayerSettingsMixerDeviceList(int x, int y, int width, int height) { 13 | super(x, y, width, height, 20, 20); 14 | player = MusicPlayerManager.getPlayer(); 15 | AudioUtil.findAudioDevices(player.getSpeakerInfo()).stream().map(GuiMusicPlayerSettingsMixerDeviceListEntry::new).peek(entry -> { 16 | if (entry.getMixerName().equals(player.getMixer())) { 17 | super.setSelected(entry); 18 | } 19 | }).forEach(this::addEntry); 20 | } 21 | 22 | @Override 23 | public void setSelected(GuiMusicPlayerSettingsMixerDeviceListEntry entry) { 24 | super.setSelected(entry); 25 | player.setMixer(entry.getMixerName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | url = "https://repo.u-team.info" 5 | } 6 | maven { 7 | url = "https://maven.neoforged.net/releases" 8 | } 9 | maven { 10 | url = "https://maven.minecraftforge.net" 11 | } 12 | maven { 13 | url = "https://maven.fabricmc.net" 14 | } 15 | maven { 16 | url = "https://maven.parchmentmc.org" 17 | } 18 | mavenCentral() 19 | gradlePluginPortal() 20 | } 21 | plugins { 22 | id "org.gradle.toolchains.foojay-resolver-convention" version "1.0.0" 23 | 24 | id "net.neoforged.gradle.userdev" version "7.0.+" 25 | 26 | id "net.minecraftforge.gradle" version "6.0.+" 27 | id "org.parchmentmc.librarian.forgegradle" version "1.+" 28 | id "org.spongepowered.mixin" version "0.7.+" 29 | 30 | id "fabric-loom" version "1.10.+" 31 | 32 | id "info.u_team.gradle_files" version "4.0.6" 33 | 34 | id "me.modmuss50.mod-publish-plugin" version "0.8.4" 35 | } 36 | } 37 | 38 | plugins { 39 | id "org.gradle.toolchains.foojay-resolver-convention" 40 | id "info.u_team.gradle_files" 41 | } 42 | 43 | gradlefiles.setupProject("Music-Player", "common", "neoforge", "forge", "fabric") 44 | 45 | include("musicplayer-lavaplayer-api", "musicplayer-lavaplayer") -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/controls/GuiVolumeSlider.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.controls; 2 | 3 | import info.u_team.u_team_core.gui.elements.USlider; 4 | import net.minecraft.client.Minecraft; 5 | import net.minecraft.client.resources.sounds.SimpleSoundInstance; 6 | import net.minecraft.network.chat.Component; 7 | import net.minecraft.sounds.SoundEvents; 8 | 9 | public class GuiVolumeSlider extends USlider { 10 | 11 | private boolean clicked; 12 | 13 | public GuiVolumeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double value, boolean decimalPrecision, boolean drawDescription, OnSliderChange slider) { 14 | super(x, y, width, height, prefix, suffix, minValue, maxValue, value, decimalPrecision, drawDescription, slider); 15 | } 16 | 17 | @Override 18 | public void onClick(double mouseX, double mouseY) { 19 | super.onClick(mouseX, mouseY); 20 | clicked = true; 21 | } 22 | 23 | @Override 24 | public void onRelease(double mouseX, double mouseY) { 25 | if (isHoveredOrFocused() && clicked) { 26 | Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1)); 27 | } 28 | clicked = false; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/init/MusicPlayerClientConstruct.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.music_player.MusicPlayerMod; 4 | import info.u_team.music_player.config.ClientConfig; 5 | import info.u_team.music_player.dependency.DependencyManager; 6 | import info.u_team.music_player.musicplayer.MusicPlayerInitManager; 7 | import info.u_team.u_team_core.api.construct.Construct; 8 | import info.u_team.u_team_core.api.construct.ModConstruct; 9 | import info.u_team.u_team_core.util.registry.BusRegister; 10 | import net.neoforged.fml.ModLoadingContext; 11 | import net.neoforged.fml.config.ModConfig.Type; 12 | 13 | @Construct(modid = MusicPlayerMod.MODID, client = true) 14 | public class MusicPlayerClientConstruct implements ModConstruct { 15 | 16 | @Override 17 | public void construct() { 18 | System.setProperty("http.agent", "Chrome"); 19 | 20 | ModLoadingContext.get().getActiveContainer().registerConfig(Type.CLIENT, ClientConfig.CONFIG); 21 | 22 | DependencyManager.load(); 23 | 24 | BusRegister.registerMod(MusicPlayerInitManager::registerMod); 25 | BusRegister.registerMod(MusicPlayerKeys::registerMod); 26 | 27 | BusRegister.registerNeoForge(MusicPlayerEventHandler::registerNeoForge); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/util/WrappedObject.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.util; 2 | 3 | import java.util.Collection; 4 | 5 | import com.google.gson.annotations.SerializedName; 6 | 7 | /** 8 | * This class holds an object. This class is immutable. To get the object use {@link #get()}. This method use the 9 | * default implementation of {@link #hashCode()} and {@link #equals(Object)}. This ensures there can't be 10 | * {@link WrappedObject} which are equals. This can be used in the Collection Framework {@link Collection} for some 11 | * special use. 12 | * 13 | * @author HyCraftHD 14 | * @param 15 | */ 16 | public class WrappedObject { 17 | 18 | /** 19 | * Wrapped object
20 | * Annotation sets the gson default serialization to o. 21 | */ 22 | @SerializedName(value = "o", alternate = { "object" }) 23 | private final T object; 24 | 25 | /** 26 | * Creates a new {@link WrappedObject} 27 | * 28 | * @param object The object you want to wrap. Must match the generic type 29 | */ 30 | public WrappedObject(T object) { 31 | this.object = object; 32 | } 33 | 34 | /** 35 | * Retrieves the wrapped object 36 | * 37 | * @return Wrapped object 38 | */ 39 | public T get() { 40 | return object; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/init/MusicPlayerClientConstruct.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.music_player.MusicPlayerMod; 4 | import info.u_team.music_player.config.ClientConfig; 5 | import info.u_team.music_player.dependency.DependencyManager; 6 | import info.u_team.music_player.musicplayer.MusicPlayerInitManager; 7 | import info.u_team.u_team_core.api.construct.Construct; 8 | import info.u_team.u_team_core.api.construct.ModConstruct; 9 | import info.u_team.u_team_core.util.registry.BusRegister; 10 | import net.minecraftforge.fml.ModLoadingContext; 11 | import net.minecraftforge.fml.config.ModConfig.Type; 12 | 13 | @Construct(modid = MusicPlayerMod.MODID, client = true) 14 | public class MusicPlayerClientConstruct implements ModConstruct { 15 | 16 | @SuppressWarnings("removal") 17 | // TODO remove later 18 | @Override 19 | public void construct() { 20 | System.setProperty("http.agent", "Chrome"); 21 | 22 | ModLoadingContext.get().registerConfig(Type.CLIENT, ClientConfig.CONFIG); 23 | 24 | DependencyManager.load(); 25 | 26 | BusRegister.registerMod(MusicPlayerInitManager::registerMod); 27 | BusRegister.registerMod(MusicPlayerKeys::registerMod); 28 | 29 | BusRegister.registerForge(MusicPlayerEventHandler::registerForge); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/impl/AudioTrackInfoImpl.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.impl; 2 | 3 | import com.sedmelluq.discord.lavaplayer.track.AudioTrackInfo; 4 | 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackInfo; 6 | 7 | public class AudioTrackInfoImpl implements IAudioTrackInfo { 8 | 9 | private final AudioTrackInfo info; 10 | 11 | public AudioTrackInfoImpl(AudioTrackInfo info) { 12 | this.info = info; 13 | } 14 | 15 | @Override 16 | public String getTitle() { 17 | return info.title; 18 | } 19 | 20 | @Override 21 | public String getAuthor() { 22 | return info.author; 23 | } 24 | 25 | @Override 26 | public String getIdentifier() { 27 | return info.identifier; 28 | } 29 | 30 | @Override 31 | public String getURI() { 32 | return info.uri; 33 | } 34 | 35 | @Override 36 | public boolean isStream() { 37 | return info.isStream; 38 | } 39 | 40 | @Override 41 | public String getFixedTitle() { 42 | if (info.title == null || info.title.equals("Unknown title")) { 43 | return info.uri; 44 | } 45 | return info.title; 46 | } 47 | 48 | @Override 49 | public String getFixedAuthor() { 50 | if (info.author == null || info.author.equals("Unknown artist")) { 51 | return ""; 52 | } 53 | return info.author; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/BetterNestedGui.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import java.util.Collection; 4 | import java.util.stream.Collectors; 5 | 6 | import net.minecraft.client.gui.components.events.ContainerEventHandler; 7 | import net.minecraft.client.gui.components.events.GuiEventListener; 8 | 9 | public interface BetterNestedGui extends ContainerEventHandler { 10 | 11 | default Collection getEventListenersForPos(double mouseX, double mouseY) { 12 | return children().stream().filter(listener -> listener.isMouseOver(mouseX, mouseY)).collect(Collectors.toList()); 13 | } 14 | 15 | @Override 16 | public default boolean mouseReleased(double mouseX, double mouseY, int button) { 17 | setDragging(false); 18 | final Collection list = getEventListenersForPos(mouseX, mouseY); 19 | getEventListenersForPos(mouseX, mouseY).forEach(listener -> listener.mouseReleased(mouseX, mouseY, button)); 20 | return !list.isEmpty(); 21 | } 22 | 23 | @Override 24 | public default boolean mouseScrolled(double mouseX, double mouseY, double button, double value) { 25 | final Collection list = getEventListenersForPos(mouseX, mouseY); 26 | getEventListenersForPos(mouseX, mouseY).forEach(listener -> listener.mouseScrolled(mouseX, mouseY, button, value)); 27 | return !list.isEmpty(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/impl/PlayingTrackImpl.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.impl; 2 | 3 | import com.sedmelluq.discord.lavaplayer.track.AudioTrack; 4 | 5 | import info.u_team.music_player.lavaplayer.MusicPlayer; 6 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 7 | import info.u_team.music_player.lavaplayer.api.audio.IPlayingTrack; 8 | 9 | public class PlayingTrackImpl extends AudioTrackImpl implements IPlayingTrack { 10 | 11 | private final MusicPlayer musicPlayer; 12 | 13 | public PlayingTrackImpl(MusicPlayer musicPlayer, AudioTrack track) { 14 | super(track); 15 | this.musicPlayer = musicPlayer; 16 | } 17 | 18 | @Override 19 | public IAudioTrack getOriginalTrack() { 20 | return track.getUserData(IAudioTrack.class); 21 | } 22 | 23 | @Override 24 | public long getPosition() { 25 | final long position; 26 | if (track.isSeekable()) { 27 | position = musicPlayer.getCurrentTrackPosition(); 28 | } else { 29 | position = super.getPosition(); 30 | } 31 | return Math.max(0, Math.min(super.getDuration(), position)); 32 | } 33 | 34 | @Override 35 | public void setPosition(long position) { 36 | if (track.isSeekable()) { 37 | position = Math.max(0, Math.min(super.getDuration(), position)); 38 | super.setPosition(position); 39 | musicPlayer.setCurrentTrackPosition(position); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [1.21.1-2.7.1.351] - 2025-11-07 5 | ### Changed 6 | - Update youtube source manager to 1.16.0 7 | - Update lavaplayer to 2.2.4-fix-j8 8 | - Soundcloud is still broken :( 9 | 10 | ## [1.21.1-2.7.1.340] - 2025-05-22 11 | ### Changed 12 | - Updated youtube source manager to 1.13.2 13 | - Fixed playback issues for youtube 14 | - Updated lavaplayer to 2.2.3-j8 15 | - Soundcloud playback sometimes breaks (no fix yet) 16 | - Update and futureproof gradle scripts and plugins 17 | - Update uteamcore 18 | 19 | ## [1.21.1-2.7.1.329] - 2025-04-06 20 | ### Changed 21 | - Updated youtube source manager to 1.12.0 22 | - Fixed playback issues 23 | - Update gradle wrapper 24 | - Update slf4j 25 | - Update uteamcore 26 | 27 | ## [1.21.1-2.7.1.318] - 2025-02-01 28 | ### Changed 29 | - Updated youtube source manager to 1.11.4 30 | - Fixed playback issues 31 | - Update gradle wrapper 32 | - Update required uteamcore version 33 | 34 | ## [1.21.1-2.7.1.307] - 2025-01-11 35 | ### Changed 36 | - Update uteamcore & fix data generated files 37 | 38 | ## [1.21.1-2.7.1.306] - 2025-01-04 39 | ### Changed 40 | - Port to 1.21.1 41 | - Add turkish translation thanks to RuyaSavascisi 42 | - Updated youtube source manager to 1.11.3 43 | - Update year 44 | - If youtube playpack fails, please try to restart your router to get a new ip address. Most likely it was blocked by youtube -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryPlaylistTrack.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 5 | import info.u_team.music_player.musicplayer.playlist.Playlist; 6 | import info.u_team.music_player.musicplayer.playlist.Playlists; 7 | import net.minecraft.client.gui.GuiGraphics; 8 | 9 | public class GuiMusicPlaylistListEntryPlaylistTrack extends GuiMusicPlaylistListEntryPlayable { 10 | 11 | private final GuiMusicPlaylistListEntryPlaylistStart start; 12 | 13 | private final IAudioTrack track; 14 | 15 | public GuiMusicPlaylistListEntryPlaylistTrack(GuiMusicPlaylistListEntryPlaylistStart start, Playlists playlists, Playlist playlist, LoadedTracks loadedTrack, IAudioTrack track) { 16 | super(playlists, playlist, loadedTrack, track); 17 | this.start = start; 18 | this.track = track; 19 | } 20 | 21 | @Override 22 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 23 | super.render(guiGraphics, slotIndex, entryY, entryX, entryWidth, entryHeight, mouseX, mouseY, hovered, partialTicks); 24 | addTrackInfo(guiGraphics, track, entryX, entryY, entryWidth, 15, isPlaying() ? 0xe02626 : 0x42F4F1); 25 | } 26 | 27 | public GuiMusicPlaylistListEntryPlaylistStart getStart() { 28 | return start; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/zh_tw.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "音量", 3 | "gui.musicplayer.create_playlist.add_list": "加入播放清單", 4 | "gui.musicplayer.create_playlist.insert_name": "輸入歌曲名稱", 5 | "gui.musicplayer.playlists.entries": "條目", 6 | "gui.musicplayer.playlists.entry": "首歌曲", 7 | "gui.musicplayer.playlists.no_name": "無名", 8 | "gui.playlist.loading": "載入曲目中...", 9 | "gui.search.add_all": "添加全部", 10 | "gui.search.added": "增加曲目", 11 | "gui.search.added_all": "添加全部曲目", 12 | "gui.search.added_list": "添加曲目清單", 13 | "gui.search.header": "添加新的曲目", 14 | "gui.search.load.file": "載入檔案", 15 | "gui.search.load.folder": "載入資料夾", 16 | "gui.search.music_files": "音樂檔案", 17 | "gui.search.search.file": "開啟文件瀏覽器", 18 | "gui.search.search.search": "搜尋曲目", 19 | "gui.search.search.uri": "輸入網址以搜尋曲目", 20 | "gui.settings.mixer_device_selection": "選擇輸出設備", 21 | "gui.settings.position.down_left": "左下方", 22 | "gui.settings.position.down_right": "右下方", 23 | "gui.settings.position.overlay": "在遊戲內顯示子母畫面的位置", 24 | "gui.settings.position.up_left": "左上方", 25 | "gui.settings.position.up_right": "右上方", 26 | "gui.settings.toggle.ingame_overlay": "切換顯示遊戲內子母畫面", 27 | "gui.settings.toggle.key_in_gui": "切換子母畫面標題滾動方向", 28 | "gui.settings.toggle.menue_overlay": "切換顯示在遊戲目錄中的選單", 29 | "gui.track.duration_undefined": "未定義", 30 | "key.musicplayer.category": "音樂播放器", 31 | "key.musicplayer.open": "開啟音樂播放器", 32 | "key.musicplayer.pause": "暫停音樂播放", 33 | "key.musicplayer.skip.back": "跳轉到下一首", 34 | "key.musicplayer.skip.forward": "跳轉到上一首" 35 | } 36 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "音量", 3 | "gui.musicplayer.create_playlist.add_list": "添加歌单", 4 | "gui.musicplayer.create_playlist.insert_name": "请输入歌单名称", 5 | "gui.musicplayer.playlists.entries": "首歌曲", 6 | "gui.musicplayer.playlists.entry": "首歌曲", 7 | "gui.musicplayer.playlists.no_name": "无名", 8 | "gui.playlist.loading": "歌曲加载中\u2026\u2026", 9 | "gui.search.add_all": "添加全部歌曲", 10 | "gui.search.added": "已添加歌曲", 11 | "gui.search.added_all": "已添加全部歌曲", 12 | "gui.search.added_list": "已添加歌单", 13 | "gui.search.header": "添加新歌曲", 14 | "gui.search.load.file": "加载文件", 15 | "gui.search.load.folder": "加载文件夹", 16 | "gui.search.music_files": "音乐文件", 17 | "gui.search.search.file": "打开文件资源管理器", 18 | "gui.search.search.search": "搜索歌曲", 19 | "gui.search.search.uri": "输入网址以搜索歌曲", 20 | "gui.settings.mixer_device_selection": "选择音频设备", 21 | "gui.settings.position.down_left": "左下", 22 | "gui.settings.position.down_right": "右下", 23 | "gui.settings.position.overlay": "游戏内叠加层位置", 24 | "gui.settings.position.up_left": "左上", 25 | "gui.settings.position.up_right": "右上", 26 | "gui.settings.toggle.ingame_overlay": "显示/隐藏游戏内叠加层", 27 | "gui.settings.toggle.key_in_gui": "启用/禁用 GUI 中的按键绑定", 28 | "gui.settings.toggle.menue_overlay": "显示/隐藏菜单中的叠加层", 29 | "gui.track.duration_undefined": "未定义", 30 | "key.musicplayer.category": "音乐播放器", 31 | "key.musicplayer.open": "打开音乐播放器", 32 | "key.musicplayer.pause": "暂停音乐播放器", 33 | "key.musicplayer.skip.back": "上一首", 34 | "key.musicplayer.skip.forward": "下一首" 35 | } 36 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/ko_kr.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "볼륨", 3 | "gui.musicplayer.create_playlist.add_list": "플레이리스트 추가", 4 | "gui.musicplayer.create_playlist.insert_name": "이름 입력", 5 | "gui.musicplayer.playlists.entries": "항목", 6 | "gui.musicplayer.playlists.entry": "항목", 7 | "gui.musicplayer.playlists.no_name": "이름 없음", 8 | "gui.playlist.loading": "트랙 불러오는 중 ...", 9 | "gui.search.add_all": "모두 추가", 10 | "gui.search.added": "트랙 추가됨", 11 | "gui.search.added_all": "모든 트랙 추가됨", 12 | "gui.search.added_list": "트랙 리스트 추가됨", 13 | "gui.search.header": "새 트랙 추가", 14 | "gui.search.load.file": "파일 불러오기", 15 | "gui.search.load.folder": "폴더 불러오기", 16 | "gui.search.music_files": "음악 파일", 17 | "gui.search.search.file": "파일 탐색기 열기", 18 | "gui.search.search.search": "트랙 검색", 19 | "gui.search.search.uri": "트랙 url 입력", 20 | "gui.settings.mixer_device_selection": "오디오 장치 선택", 21 | "gui.settings.position.down_left": "왼쪽 아래", 22 | "gui.settings.position.down_right": "오른쪽 아래", 23 | "gui.settings.position.overlay": "인게임 오버레이 위치", 24 | "gui.settings.position.up_left": "왼쪽 위", 25 | "gui.settings.position.up_right": "오른쪽 위", 26 | "gui.settings.toggle.ingame_overlay": "인게임 오버레이 토글", 27 | "gui.settings.toggle.key_in_gui": "gui에서 단축키 토글", 28 | "gui.settings.toggle.menue_overlay": "메뉴 오버레이 토글", 29 | "gui.track.duration_undefined": "확인되지 않음", 30 | "key.musicplayer.category": "음악 플레이어", 31 | "key.musicplayer.open": "음악 플레이어 열기", 32 | "key.musicplayer.pause": "음악 플레이어 일시 중지", 33 | "key.musicplayer.skip.back": "뒤로 건너뛰기", 34 | "key.musicplayer.skip.forward": "앞으로 건너뛰기" 35 | } -------------------------------------------------------------------------------- /forge/src/main/resources/META-INF/mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[52,)" 3 | issueTrackerURL="https://github.com/MC-U-Team/Music-Player/issues" 4 | license="Apache-2.0 License" 5 | 6 | [[mods]] 7 | modId="musicplayer" 8 | version="${file.jarVersion}" 9 | displayName="Music Player" 10 | displayURL="https://u-team.info/mods/musicplayer" 11 | updateJSONURL="https://api.u-team.info/update/musicplayer.json" 12 | logoFile="logo.png" 13 | credits="Thanks to sedmelluq for making lavaplayer" 14 | authors="HyCraftHD" 15 | description="Join our discord server here: https://discord.hycrafthd.net\n\nPlay every youtube video, livestream and more with this player! We use lava player to ensure this diversity.\n\nLearn more about lavaplayer here: https://github.com/sedmelluq/lavaplayer\n\nSources:\n - YouTube\n - SoundCloud\n - Bandcamp\n - Vimeo\n - Twitch streams\n - Local files\n - HTTP URLs\n\nFile formats:\n - MP3\n - FLAC\n - WAV\n - Matroska/WebM (AAC, Opus or Vorbis codecs)\n - MP4/M4A (AAC codec)\n - OGG streams (Opus, Vorbis and FLAC codecs)\n - AAC streams\n - Stream playlists (M3U and PLS)" 16 | 17 | [[dependencies.musicplayer]] 18 | modId="forge" 19 | mandatory=true 20 | versionRange="[52.0.39,)" 21 | ordering="NONE" 22 | side="BOTH" 23 | 24 | [[dependencies.musicplayer]] 25 | modId="minecraft" 26 | mandatory=true 27 | versionRange="[1.21.1]" 28 | ordering="NONE" 29 | side="BOTH" 30 | 31 | [[dependencies.musicplayer]] 32 | modId="uteamcore" 33 | mandatory=true 34 | versionRange="[5.6.2.364,)" 35 | ordering="NONE" 36 | side="BOTH" -------------------------------------------------------------------------------- /neoforge/src/main/resources/META-INF/neoforge.mods.toml: -------------------------------------------------------------------------------- 1 | modLoader="javafml" 2 | loaderVersion="[2,)" 3 | issueTrackerURL="https://github.com/MC-U-Team/Music-Player/issues" 4 | license="Apache-2.0 License" 5 | 6 | [[mods]] 7 | modId="musicplayer" 8 | version="${file.jarVersion}" 9 | displayName="Music Player" 10 | displayURL="https://u-team.info/mods/musicplayer" 11 | updateJSONURL="https://api.u-team.info/update/musicplayer_neoforge.json" 12 | logoFile="logo.png" 13 | credits="Thanks to sedmelluq for making lavaplayer" 14 | authors="HyCraftHD" 15 | description="Join our discord server here: https://discord.hycrafthd.net\n\nPlay every youtube video, livestream and more with this player! We use lava player to ensure this diversity.\n\nLearn more about lavaplayer here: https://github.com/sedmelluq/lavaplayer\n\nSources:\n - YouTube\n - SoundCloud\n - Bandcamp\n - Vimeo\n - Twitch streams\n - Local files\n - HTTP URLs\n\nFile formats:\n - MP3\n - FLAC\n - WAV\n - Matroska/WebM (AAC, Opus or Vorbis codecs)\n - MP4/M4A (AAC codec)\n - OGG streams (Opus, Vorbis and FLAC codecs)\n - AAC streams\n - Stream playlists (M3U and PLS)" 16 | 17 | [[dependencies.musicplayer]] 18 | modId="neoforge" 19 | type="required" 20 | versionRange="[21.1.93,)" 21 | ordering="NONE" 22 | side="BOTH" 23 | 24 | [[dependencies.musicplayer]] 25 | modId="minecraft" 26 | type="required" 27 | versionRange="[1.21.1]" 28 | ordering="NONE" 29 | side="BOTH" 30 | 31 | [[dependencies.musicplayer]] 32 | modId="uteamcore" 33 | type="required" 34 | versionRange="[5.6.2.364,)" 35 | ordering="NONE" 36 | side="BOTH" -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/MusicPlayerUtils.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 5 | import info.u_team.music_player.musicplayer.playlist.Playlist; 6 | import info.u_team.music_player.musicplayer.playlist.Skip; 7 | 8 | public final class MusicPlayerUtils { 9 | 10 | public static void skipForward() { 11 | final ITrackManager manager = MusicPlayerManager.getPlayer().getTrackManager(); 12 | final Playlist playlist = MusicPlayerManager.getPlaylistManager().getPlaylists().getPlaying(); 13 | if (playlist != null) { 14 | if (playlist.skip(Skip.FORWARD)) { 15 | manager.skip(); 16 | } 17 | } 18 | } 19 | 20 | public static void skipBack() { 21 | final ITrackManager manager = MusicPlayerManager.getPlayer().getTrackManager(); 22 | final Playlist playlist = MusicPlayerManager.getPlaylistManager().getPlaylists().getPlaying(); 23 | if (playlist != null) { 24 | final IAudioTrack currentlyPlaying = manager.getCurrentTrack(); 25 | 26 | if (currentlyPlaying == null) { 27 | return; 28 | } 29 | 30 | long maxDuration = currentlyPlaying.getDuration() / 10; 31 | if (maxDuration > 10000) { 32 | maxDuration = 10000; 33 | } 34 | 35 | if (currentlyPlaying.getPosition() > maxDuration && !currentlyPlaying.getInfo().isStream()) { 36 | currentlyPlaying.setPosition(0); 37 | } else { 38 | if (playlist.skip(Skip.PREVIOUS)) { 39 | manager.skip(); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/settings/IngameOverlayPosition.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.settings; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SETTINGS_POSITION_DOWN_LEFT; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SETTINGS_POSITION_DOWN_RIGHT; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SETTINGS_POSITION_UP_LEFT; 6 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SETTINGS_POSITION_UP_RIGHT; 7 | 8 | public enum IngameOverlayPosition { 9 | 10 | UP_LEFT(GUI_SETTINGS_POSITION_UP_LEFT), 11 | UP_RIGHT(GUI_SETTINGS_POSITION_UP_RIGHT), 12 | DOWN_RIGHT(GUI_SETTINGS_POSITION_DOWN_RIGHT), 13 | DOWN_LEFT(GUI_SETTINGS_POSITION_DOWN_LEFT); 14 | 15 | private final String localization; 16 | 17 | private IngameOverlayPosition(String localization) { 18 | this.localization = localization; 19 | } 20 | 21 | public String getLocalization() { 22 | return localization; 23 | } 24 | 25 | public boolean isUp() { 26 | return this == UP_LEFT || this == UP_RIGHT; 27 | } 28 | 29 | public boolean isLeft() { 30 | return this == UP_LEFT || this == DOWN_LEFT; 31 | } 32 | 33 | public static IngameOverlayPosition forwardCycle(IngameOverlayPosition position) { 34 | if (position == UP_LEFT) { 35 | position = UP_RIGHT; 36 | } else if (position == UP_RIGHT) { 37 | position = DOWN_RIGHT; 38 | } else if (position == DOWN_RIGHT) { 39 | position = DOWN_LEFT; 40 | } else { 41 | position = UP_LEFT; 42 | } 43 | return position; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/init/MusicPlayerKeys.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_CATEGORY; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_OPEN; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_PAUSE; 6 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_BACK; 7 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_FORWARD; 8 | 9 | import org.lwjgl.glfw.GLFW; 10 | 11 | import com.mojang.blaze3d.platform.InputConstants; 12 | 13 | import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper; 14 | import net.minecraft.client.KeyMapping; 15 | 16 | public class MusicPlayerKeys { 17 | 18 | public static final KeyMapping OPEN = new KeyMapping(KEY_OPEN, GLFW.GLFW_KEY_F8, KEY_CATEGORY); 19 | // TODO check to add modifier key ALT back 20 | public static final KeyMapping PAUSE = new KeyMapping(KEY_PAUSE, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, KEY_CATEGORY); 21 | public static final KeyMapping SKIP_FORWARD = new KeyMapping(KEY_SKIP_FORWARD, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_9, KEY_CATEGORY); 22 | public static final KeyMapping SKIP_BACK = new KeyMapping(KEY_SKIP_BACK, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_7, KEY_CATEGORY); 23 | 24 | public static void register() { 25 | KeyBindingHelper.registerKeyBinding(OPEN); 26 | KeyBindingHelper.registerKeyBinding(PAUSE); 27 | KeyBindingHelper.registerKeyBinding(SKIP_FORWARD); 28 | KeyBindingHelper.registerKeyBinding(SKIP_BACK); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/playlist/Playlists.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.playlist; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import com.google.common.collect.Iterators; 8 | 9 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 10 | 11 | public class Playlists implements Iterable { 12 | 13 | private final List playlists; 14 | 15 | private transient boolean locked; 16 | private transient Playlist playing; 17 | 18 | public Playlists() { 19 | playlists = new ArrayList<>(); 20 | } 21 | 22 | public int size() { 23 | return playlists.size(); 24 | } 25 | 26 | public Playlist get(int index) { 27 | return playlists.get(index); 28 | } 29 | 30 | public void add(Playlist playlist) { 31 | playlists.add(playlist); 32 | save(); 33 | } 34 | 35 | public void remove(Playlist playlist) { 36 | playlists.remove(playlist); 37 | save(); 38 | } 39 | 40 | public void setPlayingLock() { 41 | locked = true; 42 | } 43 | 44 | public void removePlayingLock() { 45 | locked = false; 46 | } 47 | 48 | public boolean isPlayingLock() { 49 | return locked; 50 | } 51 | 52 | public void setPlaying(Playlist playing) { 53 | this.playing = playing; 54 | } 55 | 56 | public Playlist getPlaying() { 57 | return playing; 58 | } 59 | 60 | @Override 61 | public Iterator iterator() { 62 | return Iterators.unmodifiableIterator(playlists.iterator()); 63 | } 64 | 65 | private void save() { 66 | MusicPlayerManager.getPlaylistManager().writeToFile(); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Create a bug report 3 | labels: ["bug"] 4 | title: "[MC-Version] " 5 | assignees: 6 | - hycrafthd 7 | body: 8 | - type: textarea 9 | id: bug_description 10 | attributes: 11 | label: Bug description and reproduction steps 12 | description: What is not working correctly? How can we trigger this bug? 13 | placeholder: | 14 | 1. 15 | 2. 16 | 3. 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | id: logs 22 | attributes: 23 | label: Log files and Screenshots 24 | description: Please upload logs, crashlogs and screenshots 25 | placeholder: Logs and screenshots 26 | validations: 27 | required: true 28 | 29 | - type: dropdown 30 | id: minecraft_version 31 | attributes: 32 | label: Used minecraft version 33 | options: 34 | - 1.21.x 35 | - 1.20.x 36 | - 1.19.x 37 | - 1.18.x 38 | - 1.17.x 39 | - 1.16.x 40 | - 1.15.x 41 | - 1.14.x 42 | - 1.13.x 43 | - 1.12.x 44 | - 1.11.x 45 | - 1.10.x 46 | - 1.9.x 47 | - 1.8.x 48 | validations: 49 | required: false 50 | 51 | - type: input 52 | id: modloader_version 53 | attributes: 54 | label: Used forge or fabric version 55 | placeholder: "e.g. 37.0.103" 56 | validations: 57 | required: true 58 | 59 | - type: input 60 | id: mod_version 61 | attributes: 62 | label: Used mod version 63 | placeholder: "e.g. 4.0.0.198" 64 | validations: 65 | required: true -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/ja_jp.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "音量", 3 | "gui.musicplayer.create_playlist.add_list": "再生リストを追加", 4 | "gui.musicplayer.create_playlist.insert_name": "名前を入力してください", 5 | "gui.musicplayer.playlists.entries": "個", 6 | "gui.musicplayer.playlists.entry": "個", 7 | "gui.musicplayer.playlists.no_name": "名前無し", 8 | "gui.playlist.loading": "トラックをロード中...", 9 | "gui.search.add_all": "全て追加", 10 | "gui.search.added": "トラックを追加しました", 11 | "gui.search.added_all": "全てのトラックを追加しました", 12 | "gui.search.added_list": "トラックリストを追加しました", 13 | "gui.search.header": "新しいトラックを追加", 14 | "gui.search.load.file": "ファイルを読み込む", 15 | "gui.search.load.folder": "フォルダを読み込む", 16 | "gui.search.music_files": "ミュージックファイル", 17 | "gui.search.search.file": "ファイルエクスプローラーを開く", 18 | "gui.search.search.search": "トラックを検索", 19 | "gui.search.search.uri": "トラックのurl", 20 | "gui.settings.mixer_device_selection": "オーディオデバイスの選択", 21 | "gui.settings.position.down_left": "左下", 22 | "gui.settings.position.down_right": "右下", 23 | "gui.settings.position.overlay": "ゲーム中のオーバーレイの位置", 24 | "gui.settings.position.up_left": "左上", 25 | "gui.settings.position.up_right": "右上", 26 | "gui.settings.toggle.ingame_overlay": "ゲーム中のオーバーレイの切り替え", 27 | "gui.settings.toggle.key_in_gui": "Guiを開いている時のキーバインドの切り替え", 28 | "gui.settings.toggle.menue_overlay": "メニューオーバーレイの切り替え", 29 | "gui.track.duration_undefined": "未定義", 30 | "key.musicplayer.category": "ミュージックプレイヤー", 31 | "key.musicplayer.open": "ミュージックプレイヤーを開く", 32 | "key.musicplayer.pause": "ミュージックプレイヤーを止める", 33 | "key.musicplayer.skip.back": "前の曲へ", 34 | "key.musicplayer.skip.forward": "次の曲へ" 35 | } 36 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/search/GuiMusicSearchListEntry.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist.search; 2 | 3 | import info.u_team.music_player.gui.BetterScrollableListEntry; 4 | import info.u_team.music_player.gui.util.GuiTrackUtils; 5 | import info.u_team.music_player.init.MusicPlayerResources; 6 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 7 | import info.u_team.u_team_core.gui.elements.ImageButton; 8 | import net.minecraft.client.gui.GuiGraphics; 9 | import net.minecraft.network.chat.CommonComponents; 10 | import net.minecraft.network.chat.Component; 11 | 12 | abstract class GuiMusicSearchListEntry extends BetterScrollableListEntry { 13 | 14 | protected final ImageButton addTrackButton; 15 | 16 | GuiMusicSearchListEntry() { 17 | addTrackButton = addChildren(new ImageButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_ADD)); 18 | } 19 | 20 | @Override 21 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 22 | addTrackButton.setX(entryWidth - 20); 23 | addTrackButton.setY(entryY + 8); 24 | addTrackButton.render(guiGraphics, mouseX, mouseY, partialTicks); 25 | } 26 | 27 | protected void addTrackInfo(GuiGraphics guiGraphics, IAudioTrack track, int entryX, int entryY, int entryWidth, int leftMargin, int titleColor) { 28 | GuiTrackUtils.addTrackInfo(guiGraphics, track, entryX, entryY, entryWidth, leftMargin, titleColor); 29 | } 30 | 31 | @Override 32 | public Component getNarration() { 33 | return CommonComponents.EMPTY; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /fabric/src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "musicplayer", 4 | "version": "${version}", 5 | "name": "Music Player", 6 | "description": "Join our discord server here: https://discord.hycrafthd.net\n\nPlay every youtube video, livestream and more with this player! We use lava player to ensure this diversity.\n\nLearn more about lavaplayer here: https://github.com/sedmelluq/lavaplayer\n\nSources:\n - YouTube\n - SoundCloud\n - Bandcamp\n - Vimeo\n - Twitch streams\n - Local files\n - HTTP URLs\n\nFile formats:\n - MP3\n - FLAC\n - WAV\n - Matroska/WebM (AAC, Opus or Vorbis codecs)\n - MP4/M4A (AAC codec)\n - OGG streams (Opus, Vorbis and FLAC codecs)\n - AAC streams\n - Stream playlists (M3U and PLS)", 7 | "authors": [ 8 | "HyCraftHD" 9 | ], 10 | "contact": { 11 | "homepage": "https://u-team.info/mods/musicplayer", 12 | "sources": "https://github.com/MC-U-Team/Music-Player", 13 | "issues": "https://github.com/MC-U-Team/Music-Player/issues" 14 | }, 15 | "license": "Apache-2.0 License", 16 | "icon": "logo.png", 17 | "environment": "client", 18 | "entrypoints": { 19 | "client": [ 20 | "info.u_team.music_player.MusicPlayerMod" 21 | ] 22 | }, 23 | "accessWidener": "musicplayer.accesswidener", 24 | "mixins": [ 25 | "musicplayer.mixins.json" 26 | ], 27 | "depends": { 28 | "uteamcore": ">=5.6.2.364", 29 | "fabricloader": ">=0.16.9", 30 | "fabric-api": ">=0.114.0+1.21.1", 31 | "minecraft": "1.21.1", 32 | "java": ">=17" 33 | }, 34 | "custom": { 35 | "uteamcore:update_url": "https://api.u-team.info/update/musicplayer_fabric.json", 36 | "modmenu": { 37 | "links": { 38 | "modmenu.discord": "https://discord.hycrafthd.net" 39 | } 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/impl/AudioTrackListImpl.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.impl; 2 | 3 | import java.util.List; 4 | import java.util.stream.Collectors; 5 | 6 | import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; 7 | 8 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 9 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackList; 10 | 11 | public class AudioTrackListImpl implements IAudioTrackList { 12 | 13 | private final String uri; 14 | private final AudioPlaylist playList; 15 | 16 | private final List tracks; 17 | 18 | private final IAudioTrack selectedTrack; 19 | 20 | public AudioTrackListImpl(AudioPlaylist playlist) { 21 | this(null, playlist); 22 | } 23 | 24 | public AudioTrackListImpl(String uri, AudioPlaylist playList) { 25 | this.uri = uri; 26 | this.playList = playList; 27 | tracks = playList.getTracks().stream().filter(track -> track != null).map(AudioTrackImpl::new).collect(Collectors.toList()); 28 | selectedTrack = playList.getSelectedTrack() != null ? new AudioTrackImpl(playList.getSelectedTrack()) : null; 29 | } 30 | 31 | @Override 32 | public String getName() { 33 | return playList.getName(); 34 | } 35 | 36 | @Override 37 | public List getTracks() { 38 | return tracks; 39 | } 40 | 41 | @Override 42 | public IAudioTrack getSelectedTrack() { 43 | return selectedTrack; 44 | } 45 | 46 | @Override 47 | public boolean isSearch() { 48 | return playList.isSearchResult(); 49 | } 50 | 51 | @Override 52 | public boolean hasUri() { 53 | return uri != null && !uri.isEmpty(); 54 | } 55 | 56 | @Override 57 | public String getUri() { 58 | return uri; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/search/SearchResult.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.search; 2 | 3 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 4 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackList; 5 | import info.u_team.music_player.lavaplayer.api.search.ISearchResult; 6 | 7 | public class SearchResult implements ISearchResult { 8 | 9 | private final String uri; 10 | 11 | private final IAudioTrackList trackList; 12 | private final IAudioTrack track; 13 | 14 | private final Exception exception; 15 | 16 | public SearchResult(String uri, Exception exception) { 17 | this(uri, null, null, exception); 18 | } 19 | 20 | public SearchResult(String uri, IAudioTrackList tracklist) { 21 | this(uri, tracklist, null, null); 22 | } 23 | 24 | public SearchResult(String uri, IAudioTrack track) { 25 | this(uri, null, track, null); 26 | } 27 | 28 | private SearchResult(String uri, IAudioTrackList trackList, IAudioTrack track, Exception exception) { 29 | this.uri = uri; 30 | this.trackList = trackList; 31 | this.track = track; 32 | this.exception = exception; 33 | } 34 | 35 | @Override 36 | public boolean isList() { 37 | return trackList != null; 38 | } 39 | 40 | @Override 41 | public IAudioTrackList getTrackList() { 42 | return trackList; 43 | } 44 | 45 | @Override 46 | public IAudioTrack getTrack() { 47 | return track; 48 | } 49 | 50 | @Override 51 | public boolean hasError() { 52 | return exception != null; 53 | } 54 | 55 | @Override 56 | public String getErrorMessage() { 57 | return exception.getMessage(); 58 | } 59 | 60 | @Override 61 | public StackTraceElement[] getStackTrace() { 62 | return exception.getStackTrace(); 63 | } 64 | 65 | @Override 66 | public String getUri() { 67 | return uri; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/BetterScrollableList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import info.u_team.u_team_core.gui.elements.ScrollableList; 4 | import net.minecraft.client.gui.components.ObjectSelectionList; 5 | import net.minecraft.util.Mth; 6 | 7 | public class BetterScrollableList> extends ScrollableList { 8 | 9 | public BetterScrollableList(int x, int y, int width, int height, int slotHeight, int sideDistance) { 10 | super(x, y, width <= 0 ? 1 : width, height <= 0 ? 1 : height, slotHeight, sideDistance); 11 | setRenderHeader(false, 0); 12 | setRenderTransparentBorder(true); 13 | } 14 | 15 | public void updateSettings(int x, int y, int width, int height) { 16 | setX(x); 17 | setY(y); 18 | setWidth(width <= 0 ? 1 : width); 19 | setHeight(height <= 0 ? 1 : height); 20 | } 21 | 22 | @Override 23 | protected boolean isValidMouseClick(int button) { 24 | return button >= 0 && button <= 2; 25 | } 26 | 27 | @Override 28 | public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { 29 | if (getFocused() != null && isDragging() && button == 0) { 30 | getFocused().mouseDragged(mouseX, mouseY, button, dragX, dragY); 31 | } 32 | if (button != 0 || !scrolling) { 33 | return false; 34 | } 35 | if (mouseY < getY()) { 36 | setScrollAmount(0.0); 37 | } else if (mouseY > getBottom()) { 38 | setScrollAmount(getMaxScroll()); 39 | } else { 40 | final double maxScroll = Math.max(1, getMaxScroll()); 41 | final int height = this.height; 42 | final int clamped = Mth.clamp((int) ((float) (height * height) / (float) getMaxPosition()), 32, height - 8); 43 | final double scoll = Math.max(1.0, maxScroll / (height - clamped)); 44 | setScrollAmount(getScrollAmount() + dragY * scoll); 45 | } 46 | return true; 47 | } 48 | } -------------------------------------------------------------------------------- /common/src/common_generated/resources/assets/musicplayer/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "Volume", 3 | "gui.musicplayer.create_playlist.add_list": "Add playlist", 4 | "gui.musicplayer.create_playlist.insert_name": "Enter a name", 5 | "gui.musicplayer.playlists.entries": "Entries", 6 | "gui.musicplayer.playlists.entry": "Entry", 7 | "gui.musicplayer.playlists.no_name": "No name", 8 | "gui.playlist.loading": "Loading tracks ...", 9 | "gui.search.add_all": "Add all", 10 | "gui.search.added": "Added track", 11 | "gui.search.added_all": "Added all tracks", 12 | "gui.search.added_list": "Added track list", 13 | "gui.search.header": "Add new tracks", 14 | "gui.search.load.file": "Load file", 15 | "gui.search.load.folder": "Load folder", 16 | "gui.search.music_files": "Music files", 17 | "gui.search.search.file": "Open file explorer", 18 | "gui.search.search.search": "Search for track", 19 | "gui.search.search.uri": "Enter url to track", 20 | "gui.settings.mixer_device_selection": "Select audio device", 21 | "gui.settings.pitch": "Playback pitch", 22 | "gui.settings.position.down_left": "Bottom left", 23 | "gui.settings.position.down_right": "Bottom right", 24 | "gui.settings.position.overlay": "Ingame overlay position", 25 | "gui.settings.position.up_left": "Top left", 26 | "gui.settings.position.up_right": "Top right", 27 | "gui.settings.speed": "Playback speed", 28 | "gui.settings.toggle.ingame_overlay": "Toggle ingame overlay", 29 | "gui.settings.toggle.key_in_gui": "Toggle keybinds in gui", 30 | "gui.settings.toggle.menue_overlay": "Toggle menue overlay", 31 | "gui.track.duration_undefined": "undefined", 32 | "key.musicplayer.category": "Music Player", 33 | "key.musicplayer.open": "Open Music Player", 34 | "key.musicplayer.pause": "Pause Music Player", 35 | "key.musicplayer.skip.back": "Skip Back", 36 | "key.musicplayer.skip.forward": "Skip Forward" 37 | } -------------------------------------------------------------------------------- /fabric/src/main/java/info/u_team/music_player/config/ClientConfig.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.config; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | 9 | import com.google.gson.Gson; 10 | import com.google.gson.GsonBuilder; 11 | 12 | import info.u_team.music_player.MusicPlayerMod; 13 | import net.fabricmc.loader.api.FabricLoader; 14 | 15 | public class ClientConfig { 16 | 17 | private static transient ClientConfig INSTANCE = new ClientConfig(); 18 | 19 | public static ClientConfig getInstance() { 20 | return INSTANCE; 21 | } 22 | 23 | public boolean internalPlaylists = false; 24 | 25 | public static void load() { 26 | final Path path = FabricLoader.getInstance().getConfigDir().resolve("musicplayer.json"); 27 | final Gson gson = new GsonBuilder().setPrettyPrinting().create(); 28 | 29 | ClientConfig config = null; 30 | 31 | try { 32 | if (!Files.exists(path)) { 33 | config = new ClientConfig(); 34 | try (final BufferedWriter writer = Files.newBufferedWriter(path)) { 35 | gson.toJson(config, writer); 36 | } 37 | } else { 38 | try (final BufferedReader reader = Files.newBufferedReader(path)) { 39 | config = gson.fromJson(reader, ClientConfig.class); 40 | } catch (final IOException ex) { 41 | throw ex; 42 | } 43 | } 44 | } catch (final IOException ex) { 45 | MusicPlayerMod.LOGGER.error("Could not read musicplayer config file at " + path, ex); 46 | } 47 | 48 | if (config == null) { 49 | config = new ClientConfig(); 50 | try (final BufferedWriter writer = Files.newBufferedWriter(path)) { 51 | gson.toJson(config, writer); 52 | } catch (final IOException ex) { 53 | } 54 | } 55 | 56 | synchronized (INSTANCE) { 57 | INSTANCE = config; 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "Ses", 3 | "gui.musicplayer.create_playlist.add_list": "Müzik ekle", 4 | "gui.musicplayer.create_playlist.insert_name": "Bir ad gir", 5 | "gui.musicplayer.playlists.entries": "Girdiler", 6 | "gui.musicplayer.playlists.entry": "Girdi", 7 | "gui.musicplayer.playlists.no_name": "Ad yok", 8 | "gui.playlist.loading": "Parçalar yükleniyor ...", 9 | "gui.search.add_all": "Hepsini ekle", 10 | "gui.search.added": "Parça eklendi", 11 | "gui.search.added_all": "Tüm parçalar eklendi", 12 | "gui.search.added_list": "Parça listesi eklendi", 13 | "gui.search.header": "Yeni parçalar ekle", 14 | "gui.search.load.file": "Dosya yükle", 15 | "gui.search.load.folder": "Klasör yükle", 16 | "gui.search.music_files": "Müzik dosyaları", 17 | "gui.search.search.file": "Dosya gezginini aç", 18 | "gui.search.search.search": "Parça ara", 19 | "gui.search.search.uri": "Parça için url gir", 20 | "gui.settings.mixer_device_selection": "Ses cihazını seç", 21 | "gui.settings.pitch": "Çalma aralığı", 22 | "gui.settings.position.down_left": "Sol alt", 23 | "gui.settings.position.down_right": "Sağ alt", 24 | "gui.settings.position.overlay": "Oyun içi arayüzü konumu", 25 | "gui.settings.position.up_left": "Sol üst", 26 | "gui.settings.position.up_right": "Sağ üst", 27 | "gui.settings.speed": "Çalma hızı", 28 | "gui.settings.toggle.ingame_overlay": "Oyun içi arayüzünü aç / kapat", 29 | "gui.settings.toggle.key_in_gui": "Tuş atamalarını gui'de aç / kapat", 30 | "gui.settings.toggle.menue_overlay": "Menü arayüzünü aç / kapat", 31 | "gui.track.duration_undefined": "tanımlanmamış", 32 | "key.musicplayer.category": "Müzik Çalar", 33 | "key.musicplayer.open": "Müzik Çaları Aç", 34 | "key.musicplayer.pause": "Müzik Çaları Duraklat", 35 | "key.musicplayer.skip.back": "Geri Atla", 36 | "key.musicplayer.skip.forward": "İleri Atla" 37 | } -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "Громкость", 3 | "gui.musicplayer.create_playlist.add_list": "Добавить плейлист", 4 | "gui.musicplayer.create_playlist.insert_name": "Введите имя", 5 | "gui.musicplayer.playlists.entries": "Записи", 6 | "gui.musicplayer.playlists.entry": "Запись", 7 | "gui.musicplayer.playlists.no_name": "Без имени", 8 | "gui.playlist.loading": "Загрузка саундтреков ...", 9 | "gui.search.add_all": "Добавить все", 10 | "gui.search.added": "Добавлен саундтрек", 11 | "gui.search.added_all": "Добавлены все саундтреки", 12 | "gui.search.added_list": "Добавлен трек лист", 13 | "gui.search.header": "Добавить новые саундтреки", 14 | "gui.search.load.file": "Загрузить файл", 15 | "gui.search.load.folder": "Загрузить папку", 16 | "gui.search.music_files": "Файлы с музыкой", 17 | "gui.search.search.file": "Открыть проводник", 18 | "gui.search.search.search": "Найти саундтрек", 19 | "gui.search.search.uri": "Введите URL саундтрека", 20 | "gui.settings.mixer_device_selection": "Выберите устройство вывода", 21 | "gui.settings.position.down_left": "Левый нижний угол", 22 | "gui.settings.position.down_right": "Правый нижний угол", 23 | "gui.settings.position.overlay": "Положение оверлея в игре", 24 | "gui.settings.position.up_left": "Левый верхний угол", 25 | "gui.settings.position.up_right": "Левый правый", 26 | "gui.settings.toggle.ingame_overlay": "Переключить оверлей в игре", 27 | "gui.settings.toggle.key_in_gui": "Переключить привязку клавиш в меню", 28 | "gui.settings.toggle.menue_overlay": "Переключить оверлей меню", 29 | "gui.track.duration_undefined": "Не определено", 30 | "key.musicplayer.category": "Музыкальный плеер", 31 | "key.musicplayer.open": "Открыть плеер", 32 | "key.musicplayer.pause": "Поставить паузу", 33 | "key.musicplayer.skip.back": "Промотать назад", 34 | "key.musicplayer.skip.forward": "Промотать вперёд" 35 | } -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/search/TrackSearch.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.search; 2 | 3 | import java.util.function.Consumer; 4 | 5 | import com.sedmelluq.discord.lavaplayer.player.AudioLoadResultHandler; 6 | import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; 7 | import com.sedmelluq.discord.lavaplayer.tools.FriendlyException; 8 | import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist; 9 | import com.sedmelluq.discord.lavaplayer.track.AudioTrack; 10 | 11 | import info.u_team.music_player.lavaplayer.api.search.ISearchResult; 12 | import info.u_team.music_player.lavaplayer.api.search.ITrackSearch; 13 | import info.u_team.music_player.lavaplayer.impl.AudioTrackImpl; 14 | import info.u_team.music_player.lavaplayer.impl.AudioTrackListImpl; 15 | 16 | public class TrackSearch implements ITrackSearch { 17 | 18 | private final AudioPlayerManager audioPlayerManager; 19 | 20 | public TrackSearch(AudioPlayerManager audioplayermanager) { 21 | audioPlayerManager = audioplayermanager; 22 | } 23 | 24 | @Override 25 | public void getTracks(String uri, Consumer consumer) { 26 | audioPlayerManager.loadItem(uri, new AudioLoadResultHandler() { 27 | 28 | @Override 29 | public void trackLoaded(AudioTrack track) { 30 | consumer.accept(new SearchResult(uri, new AudioTrackImpl(track))); 31 | } 32 | 33 | @Override 34 | public void playlistLoaded(AudioPlaylist playlist) { 35 | consumer.accept(new SearchResult(uri, new AudioTrackListImpl(uri, playlist))); 36 | } 37 | 38 | @Override 39 | public void noMatches() { 40 | consumer.accept(new SearchResult(uri, new RuntimeException("No matches found"))); 41 | } 42 | 43 | @Override 44 | public void loadFailed(FriendlyException exception) { 45 | consumer.accept(new SearchResult(uri, exception)); 46 | } 47 | }); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/SettingsManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | 9 | import org.apache.logging.log4j.LogManager; 10 | import org.apache.logging.log4j.Logger; 11 | 12 | import com.google.gson.Gson; 13 | 14 | import info.u_team.music_player.musicplayer.settings.Settings; 15 | 16 | public class SettingsManager implements IGsonLoadable { 17 | 18 | private static final Logger LOGGER = LogManager.getLogger(); 19 | 20 | private final Gson gson; 21 | 22 | private Path path; 23 | 24 | private Settings settings; 25 | 26 | SettingsManager(Gson gson) { 27 | this.gson = gson; 28 | } 29 | 30 | @Override 31 | public void setBasePath(Path basePath) { 32 | path = basePath.resolve("settings.json"); 33 | } 34 | 35 | @Override 36 | public void loadFromFile() { 37 | try { 38 | if (!Files.exists(path)) { 39 | settings = new Settings(); 40 | writeToFile(); 41 | } else { 42 | try (final BufferedReader reader = Files.newBufferedReader(path)) { 43 | settings = gson.fromJson(reader, Settings.class); 44 | if (settings == null) { 45 | settings = new Settings(); 46 | writeToFile(); 47 | } 48 | } catch (final IOException ex) { 49 | throw ex; 50 | } 51 | } 52 | } catch (final IOException ex) { 53 | LOGGER.error("Could not ready playlist file at " + path, ex); 54 | } 55 | } 56 | 57 | @Override 58 | public void writeToFile() { 59 | try (final BufferedWriter writer = Files.newBufferedWriter(path)) { 60 | gson.toJson(settings, writer); 61 | } catch (final IOException ex) { 62 | LOGGER.error("Could not write playlist file at " + path, ex); 63 | } 64 | } 65 | 66 | public Settings getSettings() { 67 | return settings; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /forge/src/main/java/info/u_team/music_player/init/MusicPlayerKeys.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_CATEGORY; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_OPEN; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_PAUSE; 6 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_BACK; 7 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_FORWARD; 8 | 9 | import org.lwjgl.glfw.GLFW; 10 | 11 | import com.mojang.blaze3d.platform.InputConstants; 12 | 13 | import net.minecraft.client.KeyMapping; 14 | import net.minecraftforge.client.event.RegisterKeyMappingsEvent; 15 | import net.minecraftforge.client.settings.KeyConflictContext; 16 | import net.minecraftforge.client.settings.KeyModifier; 17 | import net.minecraftforge.eventbus.api.IEventBus; 18 | 19 | public class MusicPlayerKeys { 20 | 21 | public static final KeyMapping OPEN = new KeyMapping(KEY_OPEN, GLFW.GLFW_KEY_F8, KEY_CATEGORY); 22 | 23 | public static final KeyMapping PAUSE = new KeyMapping(KEY_PAUSE, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, KEY_CATEGORY); 24 | public static final KeyMapping SKIP_FORWARD = new KeyMapping(KEY_SKIP_FORWARD, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_9, KEY_CATEGORY); 25 | public static final KeyMapping SKIP_BACK = new KeyMapping(KEY_SKIP_BACK, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_7, KEY_CATEGORY); 26 | 27 | private static void register(RegisterKeyMappingsEvent event) { 28 | event.register(OPEN); 29 | event.register(PAUSE); 30 | event.register(SKIP_FORWARD); 31 | event.register(SKIP_BACK); 32 | } 33 | 34 | public static void registerMod(IEventBus bus) { 35 | bus.addListener(MusicPlayerKeys::register); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /neoforge/src/main/java/info/u_team/music_player/init/MusicPlayerKeys.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_CATEGORY; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_OPEN; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_PAUSE; 6 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_BACK; 7 | import static info.u_team.music_player.init.MusicPlayerLocalization.KEY_SKIP_FORWARD; 8 | 9 | import org.lwjgl.glfw.GLFW; 10 | 11 | import com.mojang.blaze3d.platform.InputConstants; 12 | 13 | import net.minecraft.client.KeyMapping; 14 | import net.neoforged.bus.api.IEventBus; 15 | import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; 16 | import net.neoforged.neoforge.client.settings.KeyConflictContext; 17 | import net.neoforged.neoforge.client.settings.KeyModifier; 18 | 19 | public class MusicPlayerKeys { 20 | 21 | public static final KeyMapping OPEN = new KeyMapping(KEY_OPEN, GLFW.GLFW_KEY_F8, KEY_CATEGORY); 22 | 23 | public static final KeyMapping PAUSE = new KeyMapping(KEY_PAUSE, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_8, KEY_CATEGORY); 24 | public static final KeyMapping SKIP_FORWARD = new KeyMapping(KEY_SKIP_FORWARD, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_9, KEY_CATEGORY); 25 | public static final KeyMapping SKIP_BACK = new KeyMapping(KEY_SKIP_BACK, KeyConflictContext.UNIVERSAL, KeyModifier.ALT, InputConstants.Type.KEYSYM, GLFW.GLFW_KEY_KP_7, KEY_CATEGORY); 26 | 27 | private static void register(RegisterKeyMappingsEvent event) { 28 | event.register(OPEN); 29 | event.register(PAUSE); 30 | event.register(SKIP_FORWARD); 31 | event.register(SKIP_BACK); 32 | } 33 | 34 | public static void registerMod(IEventBus bus) { 35 | bus.addListener(MusicPlayerKeys::register); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /common/src/common/resources/assets/musicplayer/lang/pt_br.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "Volume", 3 | "gui.musicplayer.create_playlist.add_list": "Adicionar lista de reprodução", 4 | "gui.musicplayer.create_playlist.insert_name": "Digite seu nome", 5 | "gui.musicplayer.playlists.entries": "Entradas", 6 | "gui.musicplayer.playlists.entry": "Entradas", 7 | "gui.musicplayer.playlists.no_name": "Sem Nome", 8 | "gui.playlist.loading": "Carregando trilhas sonoras...", 9 | "gui.search.add_all": "Adicionar tudo", 10 | "gui.search.added": "Trilha sonora adicionada", 11 | "gui.search.added_all": "Todas as trilhas sonoras adicionadas", 12 | "gui.search.added_list": "Lista de faixas adicionada", 13 | "gui.search.header": "Adicionar novas trilhas sonoras", 14 | "gui.search.load.file": "Subir arquivo", 15 | "gui.search.load.folder": "Pasta de download", 16 | "gui.search.music_files": "arquivos de música", 17 | "gui.search.search.file": "Abra o explorador", 18 | "gui.search.search.search": "Encontrar trilha sonora", 19 | "gui.search.search.uri": "Insira o URL da trilha sonora", 20 | "gui.settings.mixer_device_selection": "Selecione o dispositivo de saída", 21 | "gui.settings.position.down_left": "Canto inferior esquerdo", 22 | "gui.settings.position.down_right": "Canto inferior direito", 23 | "gui.settings.position.overlay": "Posição de sobreposição no jogo", 24 | "gui.settings.position.up_left": "Canto superior esquerdo", 25 | "gui.settings.position.up_right": "Esquerda direita", 26 | "gui.settings.toggle.ingame_overlay": "Alternar sobreposição no jogo", 27 | "gui.settings.toggle.key_in_gui": "Alternar ligação de teclas no menu", 28 | "gui.settings.toggle.menue_overlay": "Alternar sobreposição de menu", 29 | "gui.track.duration_undefined": "Indefinido", 30 | "key.musicplayer.category": "Reprodutor de música", 31 | "key.musicplayer.open": "jogador aberto", 32 | "key.musicplayer.pause": "Pausa", 33 | "key.musicplayer.skip.back": "Retroceder", 34 | "key.musicplayer.skip.forward": "Passe à frente" 35 | } -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/init/MusicPlayerResources.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import info.u_team.music_player.MusicPlayerReference; 4 | import net.minecraft.resources.ResourceLocation; 5 | 6 | public class MusicPlayerResources { 7 | 8 | public static final ResourceLocation TEXTURE_CREATE = createResource("create"); 9 | public static final ResourceLocation TEXTURE_OPEN = createResource("open"); 10 | public static final ResourceLocation TEXTURE_CLEAR = createResource("clear"); 11 | public static final ResourceLocation TEXTURE_PLAY = createResource("play"); 12 | public static final ResourceLocation TEXTURE_STOP = createResource("stop"); 13 | public static final ResourceLocation TEXTURE_PAUSE = createResource("pause"); 14 | public static final ResourceLocation TEXTURE_ADD = createResource("add"); 15 | public static final ResourceLocation TEXTURE_UP = createResource("up"); 16 | public static final ResourceLocation TEXTURE_DOWN = createResource("down"); 17 | public static final ResourceLocation TEXTURE_BACK = createResource("back"); 18 | public static final ResourceLocation TEXTURE_SKIP_FORWARD = createResource("skip-forward"); 19 | public static final ResourceLocation TEXTURE_SKIP_BACK = createResource("skip-back"); 20 | public static final ResourceLocation TEXTURE_SHUFFLE = createResource("shuffle"); 21 | public static final ResourceLocation TEXTURE_REPEAT = createResource("repeat"); 22 | public static final ResourceLocation TEXTURE_REPEAT_SINGLE = createResource("repeat-single"); 23 | public static final ResourceLocation TEXTURE_SETTINGS = createResource("settings"); 24 | 25 | public static final ResourceLocation TEXTURE_SOCIAL_YOUTUBE = createResource("socialmedia/youtube-logo"); 26 | public static final ResourceLocation TEXTURE_SOCIAL_SOUNDCLOUD = createResource("socialmedia/soundcloud-logo"); 27 | 28 | private static ResourceLocation createResource(String name) { 29 | return ResourceLocation.fromNamespaceAndPath(MusicPlayerReference.MODID, "textures/gui/" + name + ".png"); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | } 4 | 5 | sourceSets { 6 | main { 7 | java 8 | resources 9 | } 10 | test_player { 11 | java 12 | resources 13 | } 14 | } 15 | 16 | java { 17 | toolchain { 18 | languageVersion = JavaLanguageVersion.of(21) 19 | } 20 | } 21 | 22 | configurations { 23 | musicplayer 24 | musicplayer.exclude group: "commons-logging", module: "commons-logging" 25 | implementation.extendsFrom(musicplayer) 26 | } 27 | 28 | evaluationDependsOn(":musicplayer-lavaplayer-api") 29 | 30 | tasks.named("jar").configure { 31 | archiveExtension.set(archiveExtension.get() + ".packed") 32 | 33 | exclude("LICENSE-DEPENDENCIES") 34 | } 35 | 36 | tasks.register("deleteOldDependencies", Delete) { 37 | delete layout.buildDirectory.dir("dependencies").map { it.asFileTree } 38 | } 39 | 40 | tasks.register("copyNewDependencies", Copy) { 41 | dependsOn tasks.named("deleteOldDependencies") 42 | 43 | from configurations.musicplayer.copyRecursive().with { 44 | exclude group: "org.slf4j", module: "slf4j-api" 45 | } 46 | into layout.buildDirectory.dir("dependencies") 47 | rename { fileName -> 48 | fileName += ".packed" 49 | } 50 | } 51 | 52 | tasks.named("assemble").configure { 53 | dependsOn tasks.named("copyNewDependencies") 54 | } 55 | 56 | repositories { 57 | maven { 58 | url = "https://repo.u-team.info" 59 | } 60 | maven { 61 | url = "https://maven.arbjerg.dev/releases" 62 | } 63 | maven { 64 | url = "https://maven.topi.wtf/releases" 65 | } 66 | mavenCentral() 67 | maven { 68 | url = "https://jitpack.io" 69 | } 70 | } 71 | 72 | dependencies { 73 | musicplayer "net.hycrafthd.lavaplayer:lavaplayer:2.2.4-fix-j8" 74 | musicplayer "dev.lavalink.youtube:v2:1.16.0" 75 | musicplayer "dev.arbjerg:lavadsp:0.7.8" 76 | musicplayer "com.github.topi314.lavasrc:lavasrc:4.8.1" 77 | musicplayer "com.github.topi314.lavasrc:lavasrc-protocol:4.8.1" 78 | 79 | musicplayer "org.slf4j:jcl-over-slf4j:2.0.17" 80 | implementation "org.slf4j:slf4j-simple:2.0.17" 81 | 82 | implementation project(":musicplayer-lavaplayer-api") 83 | } 84 | -------------------------------------------------------------------------------- /common/src/common_generated/resources/assets/musicplayer/lang/de_de.json: -------------------------------------------------------------------------------- 1 | { 2 | "gui.controls.volume": "Lautstärke", 3 | "gui.musicplayer.create_playlist.add_list": "Füge eine Wiedergabeliste hinzu", 4 | "gui.musicplayer.create_playlist.insert_name": "Gebe einen Namen an", 5 | "gui.musicplayer.playlists.entries": "Einträge", 6 | "gui.musicplayer.playlists.entry": "Eintrag", 7 | "gui.musicplayer.playlists.no_name": "Kein Name", 8 | "gui.playlist.loading": "Lade Audioeinträge ...", 9 | "gui.search.add_all": "Füge alle Audioeinträge hinzu", 10 | "gui.search.added": "Audioeintrag hinzugefügt", 11 | "gui.search.added_all": "Alle Audioeinträge hinzugefügt", 12 | "gui.search.added_list": "Audioeintragliste hinzugefügt", 13 | "gui.search.header": "Füge neue Audioeinträge hinzu", 14 | "gui.search.load.file": "Lade eine Datei", 15 | "gui.search.load.folder": "Lade einen Ordner", 16 | "gui.search.music_files": "Musikdatein", 17 | "gui.search.search.file": "Öffne den Dateimanager", 18 | "gui.search.search.search": "Suche nach Audiodatein", 19 | "gui.search.search.uri": "Gebe eine URL zum Musikstück an", 20 | "gui.settings.mixer_device_selection": "Wähle das Audiogerät", 21 | "gui.settings.pitch": "Wiedergabetonhöhe", 22 | "gui.settings.position.down_left": "Unten Links", 23 | "gui.settings.position.down_right": "Unten Rechts", 24 | "gui.settings.position.overlay": "Ingame-Overlay Position", 25 | "gui.settings.position.up_left": "Oben Links", 26 | "gui.settings.position.up_right": "Oben Rechts", 27 | "gui.settings.speed": "Wiedergabegeschwindigkeit", 28 | "gui.settings.toggle.ingame_overlay": "Ingame-Overlay umschalten", 29 | "gui.settings.toggle.key_in_gui": "Tastenkombinationen im Gui umschalten", 30 | "gui.settings.toggle.menue_overlay": "Menü-Overlay umschalten", 31 | "gui.track.duration_undefined": "nicht definiert", 32 | "key.musicplayer.category": "Musikplayer", 33 | "key.musicplayer.open": "Öffne den Musikplayer", 34 | "key.musicplayer.pause": "Pausiere den Musikplayer", 35 | "key.musicplayer.skip.back": "Zurück spulen", 36 | "key.musicplayer.skip.forward": "Nach vorne spulen" 37 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Music-Player 2 | 3 | [ 4 | ![Curseforge Downloads](http://cf.way2muchnoise.eu/music-player.svg) 5 | ![Curseforge Versions](http://cf.way2muchnoise.eu/versions/music-player.svg) 6 | ](https://www.curseforge.com/minecraft/mc-mods/music-player) 7 | [ 8 | ![Discord](https://img.shields.io/discord/297104769649213441?label=Discord) 9 | ](https://discordapp.com/invite/QXbWS36) 10 | 11 | ### With this mod you can listen to music and manage your playlist without using external programs. 12 | 13 | - Download on [curseforge](https://www.curseforge.com/minecraft/mc-mods/music-player). 14 | - Find more information on our [website](https://u-team.info/mods/musicplayer). 15 | - Updates can be found in the [changelog](CHANGELOG.md). 16 | 17 | ### How to build this mod 18 | 19 | #### Setup Eclipse 20 | - ``./gradlew genEclipseRuns eclipse`` 21 | - Import project as existing workspace 22 | 23 | #### Setup IntelliJ IDEA 24 | - ``./gradlew genIntellijRuns`` 25 | - Import as gradle project 26 | 27 | #### Build 28 | - ``./gradlew build`` 29 | 30 | ### How to include this mod 31 | 32 | - Repository: [repo.u-team.info](https://repo.u-team.info) 33 | - Artifact: **info.u-team:music_player-${config.forge.mcversion}:${config.musicplayer.version}** 34 | - *{config.forge.mcversion}* is the minecraft version. 35 | - *{config.musicplayer.version}* is the musicplayer version. 36 | 37 | #### Using in Forge Gradle 3: 38 | ```gradle 39 | repositories { 40 | maven { url = "https://repo.u-team.info" } 41 | } 42 | 43 | dependencies { 44 | compileOnly fg.deobf("info.u-team:music_player-${config.forge.mcversion}:${config.musicplayer.version}") 45 | } 46 | ``` 47 | 48 | ### License 49 | 50 | - This mod is licensed under apache 2 license. For more information see [here](LICENSE). 51 | - This mod can be packed in any curseforge modpack you like. 52 | 53 | ### Issues 54 | 55 | - Please report issues to the [github issues](../../issues). 56 | - Include your minecraft version, forge version and mod version. 57 | - Upload your log on [gist](https://gist.github.com) or [pastebin](https://pastebin.com) and include link in your report. 58 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/search/GuiMusicSearchListEntryMusicTrack.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist.search; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SEARCH_ADDED; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 5 | 6 | import info.u_team.music_player.gui.util.GuiTrackUtils; 7 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 8 | import info.u_team.music_player.musicplayer.playlist.Playlist; 9 | import net.minecraft.ChatFormatting; 10 | import net.minecraft.client.gui.GuiGraphics; 11 | 12 | public class GuiMusicSearchListEntryMusicTrack extends GuiMusicSearchListEntry { 13 | 14 | private final IAudioTrack track; 15 | private final boolean playlistEntry; 16 | 17 | public GuiMusicSearchListEntryMusicTrack(GuiMusicSearch gui, Playlist playlist, IAudioTrack track, boolean playlistEntry) { 18 | this.track = track; 19 | this.playlistEntry = playlistEntry; 20 | addTrackButton.setPressable(() -> { 21 | playlist.add(track); 22 | gui.setInformation(ChatFormatting.GREEN + getTranslation(GUI_SEARCH_ADDED), 150); 23 | }); 24 | } 25 | 26 | @Override 27 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 28 | super.render(guiGraphics, slotIndex, entryY, entryX, entryWidth, entryHeight, mouseX, mouseY, hovered, partialTicks); 29 | addTrackInfo(guiGraphics, track, entryX, entryY, entryWidth, playlistEntry ? 15 : 5, playlistEntry ? 0x42F4F1 : 0x419BF4); 30 | } 31 | 32 | public boolean isPlaylistEntry() { 33 | return playlistEntry; 34 | } 35 | 36 | public IAudioTrack getTrack() { 37 | return track; 38 | } 39 | 40 | @Override 41 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 42 | if (button == 2) { 43 | final String uri = track.getInfo().getURI(); 44 | if (GuiTrackUtils.openURI(uri)) { 45 | return true; 46 | } 47 | } 48 | return super.mouseClicked(mouseX, mouseY, button); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/PlaylistManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.IOException; 6 | import java.io.InputStreamReader; 7 | import java.io.OutputStreamWriter; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.util.zip.GZIPInputStream; 11 | import java.util.zip.GZIPOutputStream; 12 | import java.util.zip.ZipException; 13 | 14 | import org.apache.logging.log4j.LogManager; 15 | import org.apache.logging.log4j.Logger; 16 | 17 | import com.google.gson.Gson; 18 | 19 | import info.u_team.music_player.musicplayer.playlist.Playlists; 20 | 21 | public class PlaylistManager implements IGsonLoadable { 22 | 23 | private static final Logger LOGGER = LogManager.getLogger(); 24 | 25 | private final Gson gson; 26 | 27 | private Path path; 28 | 29 | private Playlists playlists; 30 | 31 | PlaylistManager(Gson gson) { 32 | this.gson = gson; 33 | } 34 | 35 | @Override 36 | public void setBasePath(Path basePath) { 37 | path = basePath.resolve("playlist.json.gz"); 38 | } 39 | 40 | @Override 41 | public void loadFromFile() { 42 | try { 43 | if (!Files.exists(path)) { 44 | playlists = new Playlists(); 45 | writeToFile(); 46 | } else { 47 | try (final BufferedReader reader = new BufferedReader(new InputStreamReader(new GZIPInputStream(Files.newInputStream(path)), "UTF-8"))) { 48 | playlists = gson.fromJson(reader, Playlists.class); 49 | } catch (final IOException ex) { 50 | throw ex; 51 | } 52 | } 53 | } catch (final ZipException ex) { 54 | LOGGER.warn("The playlist file is corrupted and will be deleted at " + path, ex); 55 | playlists = new Playlists(); 56 | } catch (final IOException ex) { 57 | LOGGER.error("Could not read playlist file at " + path, ex); 58 | } 59 | } 60 | 61 | @Override 62 | public void writeToFile() { 63 | try (final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new GZIPOutputStream(Files.newOutputStream(path)), "UTF-8"))) { 64 | gson.toJson(playlists, writer); 65 | } catch (final IOException ex) { 66 | LOGGER.error("Could not write playlist file at " + path, ex); 67 | } 68 | } 69 | 70 | public Playlists getPlaylists() { 71 | return playlists; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryPlaylistStart.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_TRACK_DURATION_UNDEFINED; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 10 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 11 | import info.u_team.music_player.musicplayer.playlist.Playlist; 12 | import info.u_team.music_player.musicplayer.playlist.Playlists; 13 | import info.u_team.music_player.util.TimeUtil; 14 | import net.minecraft.client.gui.GuiGraphics; 15 | 16 | public class GuiMusicPlaylistListEntryPlaylistStart extends GuiMusicPlaylistListEntryFunctions { 17 | 18 | private final String name; 19 | private final String duration; 20 | 21 | private final List entries; 22 | 23 | public GuiMusicPlaylistListEntryPlaylistStart(GuiMusicPlaylistList guilist, Playlists playlists, Playlist playlist, LoadedTracks loadedTracks) { 24 | super(guilist, playlists, playlist, loadedTracks, loadedTracks.getFirstTrack()); 25 | name = loadedTracks.getTitle(); 26 | 27 | final List tracks = loadedTracks.getTrackList().getTracks(); 28 | 29 | if (!tracks.parallelStream().anyMatch(track -> track.getInfo().isStream())) { 30 | duration = TimeUtil.timeConversion(tracks.parallelStream().mapToLong(track -> track.getDuration()).sum() / 1000); 31 | } else { 32 | duration = getTranslation(GUI_TRACK_DURATION_UNDEFINED); 33 | } 34 | 35 | entries = new ArrayList<>(); 36 | } 37 | 38 | @Override 39 | public void drawEntryExtended(GuiGraphics guiGraphics, int entryX, int entryY, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean mouseInList, float partialTicks) { 40 | guiGraphics.drawString(minecraft.font, name, entryX + 5, entryY + 15, 0xF4E242, false); 41 | guiGraphics.drawString(minecraft.font, duration, entryX + entryWidth - 140, entryY + 15, 0xFFFF00, false); 42 | } 43 | 44 | public void addEntry(GuiMusicPlaylistListEntryPlaylistTrack entry) { 45 | entries.add(entry); 46 | } 47 | 48 | @Override 49 | protected boolean isPlaying() { 50 | return entries.stream().anyMatch(entry -> entry.getStart() == this && entry.getTrack() == getCurrentlyPlaying()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/queue/TrackManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.queue; 2 | 3 | import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; 4 | import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter; 5 | import com.sedmelluq.discord.lavaplayer.track.AudioTrack; 6 | import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason; 7 | 8 | import info.u_team.music_player.lavaplayer.MusicPlayer; 9 | import info.u_team.music_player.lavaplayer.api.audio.IPlayingTrack; 10 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 11 | import info.u_team.music_player.lavaplayer.api.queue.ITrackQueue; 12 | import info.u_team.music_player.lavaplayer.impl.PlayingTrackImpl; 13 | 14 | public class TrackManager extends AudioEventAdapter implements ITrackManager { 15 | 16 | private final MusicPlayer musicPlayer; 17 | 18 | private final AudioPlayer audioPlayer; 19 | 20 | private TrackQueueWrapper queueWrapper; 21 | 22 | public TrackManager(MusicPlayer musicPlayer, AudioPlayer audioPlayer) { 23 | this.musicPlayer = musicPlayer; 24 | this.audioPlayer = audioPlayer; 25 | audioPlayer.addListener(this); 26 | } 27 | 28 | @Override 29 | public void onTrackEnd(AudioPlayer player, AudioTrack track, AudioTrackEndReason endReason) { 30 | if (endReason == AudioTrackEndReason.FINISHED || endReason == AudioTrackEndReason.LOAD_FAILED) { 31 | skip(); 32 | } 33 | } 34 | 35 | @Override 36 | public void start() { 37 | setPaused(false); 38 | skip(); 39 | } 40 | 41 | @Override 42 | public void stop() { 43 | setPaused(false); 44 | audioPlayer.stopTrack(); 45 | queueWrapper = null; 46 | } 47 | 48 | @Override 49 | public void setTrackQueue(ITrackQueue queue) { 50 | if (queue == null) { 51 | queueWrapper = null; 52 | } 53 | queueWrapper = new TrackQueueWrapper(queue); 54 | } 55 | 56 | @Override 57 | public void skip() { 58 | if (queueWrapper == null) { 59 | stop(); 60 | return; 61 | } 62 | if (queueWrapper.calculateNext() && queueWrapper.getNext() != null) { 63 | audioPlayer.startTrack(queueWrapper.getNext(), false); 64 | } else { 65 | stop(); 66 | } 67 | } 68 | 69 | @Override 70 | public void setPaused(boolean value) { 71 | audioPlayer.setPaused(value); 72 | } 73 | 74 | @Override 75 | public boolean isPaused() { 76 | return audioPlayer.isPaused(); 77 | } 78 | 79 | @Override 80 | public IPlayingTrack getCurrentTrack() { 81 | return audioPlayer.getPlayingTrack() == null ? null : new PlayingTrackImpl(musicPlayer, audioPlayer.getPlayingTrack()); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/settings/Settings.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.settings; 2 | 3 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 4 | 5 | public class Settings { 6 | 7 | private int volume; 8 | 9 | private Repeat repeat; 10 | 11 | private boolean shuffle; 12 | 13 | private boolean showIngameOverlay; 14 | private boolean showIngameMenueOverlay; 15 | 16 | private IngameOverlayPosition ingameOverlayPosition; 17 | 18 | private boolean keyWorkInGui; 19 | 20 | public Settings() { 21 | volume = 10; 22 | repeat = Repeat.NO; 23 | shuffle = false; 24 | showIngameOverlay = true; 25 | showIngameMenueOverlay = false; 26 | ingameOverlayPosition = IngameOverlayPosition.DOWN_RIGHT; 27 | keyWorkInGui = true; 28 | } 29 | 30 | public int getVolume() { 31 | return volume; 32 | } 33 | 34 | public void setVolume(int volume) { 35 | this.volume = volume; 36 | save(); 37 | } 38 | 39 | public Repeat getRepeat() { 40 | return repeat; 41 | } 42 | 43 | public void setRepeat(Repeat repeat) { 44 | this.repeat = repeat; 45 | save(); 46 | } 47 | 48 | public boolean isShuffle() { 49 | return shuffle; 50 | } 51 | 52 | public void setShuffle(boolean shuffle) { 53 | this.shuffle = shuffle; 54 | save(); 55 | } 56 | 57 | public boolean isShowIngameOverlay() { 58 | return showIngameOverlay; 59 | } 60 | 61 | public void setShowIngameOverlay(boolean showIngameOverlay) { 62 | this.showIngameOverlay = showIngameOverlay; 63 | save(); 64 | } 65 | 66 | public boolean isShowIngameMenueOverlay() { 67 | return showIngameMenueOverlay; 68 | } 69 | 70 | public void setShowIngameMenueOverlay(boolean showIngameMenueOverlay) { 71 | this.showIngameMenueOverlay = showIngameMenueOverlay; 72 | save(); 73 | } 74 | 75 | public IngameOverlayPosition getIngameOverlayPosition() { 76 | return ingameOverlayPosition; 77 | } 78 | 79 | public void setIngameOverlayPosition(IngameOverlayPosition ingameOverlayPosition) { 80 | this.ingameOverlayPosition = ingameOverlayPosition; 81 | save(); 82 | } 83 | 84 | public boolean isKeyWorkInGui() { 85 | return keyWorkInGui; 86 | } 87 | 88 | public void setKeyWorkInGui(boolean keyWorkInGui) { 89 | this.keyWorkInGui = keyWorkInGui; 90 | save(); 91 | } 92 | 93 | public boolean isFinite() { 94 | return repeat == Repeat.NO; 95 | } 96 | 97 | public boolean isSingleRepeat() { 98 | return repeat == Repeat.SINGLE; 99 | } 100 | 101 | private void save() { 102 | MusicPlayerManager.getSettingsManager().writeToFile(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/search/GuiMusicSearchListEntryPlaylist.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist.search; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_SEARCH_ADDED_LIST; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_TRACK_DURATION_UNDEFINED; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 6 | 7 | import java.util.List; 8 | 9 | import info.u_team.music_player.gui.util.GuiTrackUtils; 10 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 11 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackList; 12 | import info.u_team.music_player.musicplayer.playlist.Playlist; 13 | import info.u_team.music_player.util.TimeUtil; 14 | import net.minecraft.ChatFormatting; 15 | import net.minecraft.client.gui.GuiGraphics; 16 | 17 | public class GuiMusicSearchListEntryPlaylist extends GuiMusicSearchListEntry { 18 | 19 | private final IAudioTrackList trackList; 20 | 21 | private final String name; 22 | private final String duration; 23 | 24 | public GuiMusicSearchListEntryPlaylist(GuiMusicSearch gui, Playlist playlist, IAudioTrackList trackList) { 25 | this.trackList = trackList; 26 | name = trackList.getName(); 27 | 28 | final List tracks = trackList.getTracks(); 29 | 30 | if (!tracks.parallelStream().anyMatch(track -> track.getInfo().isStream())) { 31 | duration = TimeUtil.timeConversion(tracks.parallelStream().mapToLong(track -> track.getDuration()).sum() / 1000); 32 | } else { 33 | duration = getTranslation(GUI_TRACK_DURATION_UNDEFINED); 34 | } 35 | 36 | addTrackButton.setPressable(() -> { 37 | playlist.add(trackList); 38 | gui.setInformation(ChatFormatting.GREEN + getTranslation(GUI_SEARCH_ADDED_LIST), 150); 39 | }); 40 | } 41 | 42 | @Override 43 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 44 | super.render(guiGraphics, slotIndex, entryY, entryX, entryWidth, entryHeight, mouseX, mouseY, hovered, partialTicks); 45 | guiGraphics.drawString(minecraft.font, name, entryX + 5, entryY + 15, 0xF4E242, false); 46 | guiGraphics.drawString(minecraft.font, duration, entryX + entryWidth - 135, entryY + 5, 0xFFFF00, false); 47 | } 48 | 49 | public IAudioTrackList getTrackList() { 50 | return trackList; 51 | } 52 | 53 | @Override 54 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 55 | if (button == 2) { 56 | final String uri = trackList.getUri(); 57 | if (GuiTrackUtils.openURI(uri)) { 58 | return true; 59 | } 60 | } 61 | return super.mouseClicked(mouseX, mouseY, button); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/controls/GuiMusicProgressBar.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.controls; 2 | 3 | import info.u_team.music_player.gui.util.GuiTrackUtils; 4 | import info.u_team.music_player.init.MusicPlayerColors; 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 7 | import info.u_team.u_team_core.gui.elements.ProgressBar; 8 | import info.u_team.u_team_core.gui.elements.ScalableText; 9 | import net.minecraft.client.Minecraft; 10 | import net.minecraft.client.gui.Font; 11 | import net.minecraft.client.gui.GuiGraphics; 12 | 13 | public class GuiMusicProgressBar extends ProgressBar { 14 | 15 | private final ScalableText positionRender; 16 | private final ScalableText durationRender; 17 | 18 | public GuiMusicProgressBar(ITrackManager manager, int x, int y, int width, int height, float scale) { 19 | super(x, y, width, height, MusicPlayerColors.GREY, MusicPlayerColors.GREEN, () -> getProgress(manager), (value) -> updateProgress(manager, value)); 20 | final Font fontRender = Minecraft.getInstance().font; 21 | positionRender = new ScalableText(fontRender, () -> GuiTrackUtils.getFormattedPosition(manager.getCurrentTrack()), x, y); 22 | positionRender.setScale(scale); 23 | positionRender.setColor(MusicPlayerColors.YELLOW); 24 | positionRender.setTextChanged(renderer -> { 25 | renderer.setX(getX() - renderer.getTextWidth() - (renderer.getScale() < 1 ? 3 : 5)); 26 | renderer.setY(getY() - (renderer.getScale() < 1 ? 1 : 2)); 27 | }); 28 | durationRender = new ScalableText(fontRender, () -> GuiTrackUtils.getFormattedDuration(manager.getCurrentTrack()), x, y); 29 | durationRender.setScale(scale); 30 | durationRender.setColor(MusicPlayerColors.YELLOW); 31 | durationRender.setTextChanged(renderer -> { 32 | renderer.setX(getX() + getWidth() + (renderer.getScale() < 1 ? 3 : 5)); 33 | renderer.setY(getY() - (renderer.getScale() < 1 ? 1 : 2)); 34 | }); 35 | } 36 | 37 | @Override 38 | public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 39 | super.render(guiGraphics, mouseX, mouseY, partialTicks); 40 | 41 | positionRender.render(guiGraphics, mouseX, mouseY, partialTicks); 42 | durationRender.render(guiGraphics, mouseX, mouseY, partialTicks); 43 | } 44 | 45 | private static double getProgress(ITrackManager manager) { 46 | final IAudioTrack track = manager.getCurrentTrack(); 47 | if (track == null) { 48 | return 0; 49 | } 50 | if (track.getInfo().isStream()) { 51 | return 0.5; 52 | } 53 | return (double) track.getPosition() / track.getDuration(); 54 | } 55 | 56 | private static void updateProgress(ITrackManager manager, double value) { 57 | final IAudioTrack track = manager.getCurrentTrack(); 58 | if (track != null) { 59 | track.setPosition((long) (track.getDuration() * value)); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/MusicPlayerManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer; 2 | 3 | import org.apache.logging.log4j.Level; 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.Logger; 6 | import org.apache.logging.log4j.core.LoggerContext; 7 | import org.apache.logging.log4j.core.config.LoggerConfig; 8 | 9 | import com.google.gson.Gson; 10 | import com.google.gson.GsonBuilder; 11 | 12 | import info.u_team.music_player.lavaplayer.api.IMusicPlayer; 13 | 14 | public class MusicPlayerManager { 15 | 16 | private static final Logger LOGGER = LogManager.getLogger(); 17 | 18 | private static IMusicPlayer player; 19 | 20 | private static final Gson gson = new GsonBuilder().setPrettyPrinting().create(); 21 | 22 | private static final MusicPlayerFiles files = new MusicPlayerFiles(); 23 | 24 | private static final PlaylistManager playListManager = new PlaylistManager(gson); 25 | private static final SettingsManager settingsManager = new SettingsManager(gson); 26 | 27 | static void setup(ClassLoader classLoader, boolean internalPlaylists) { 28 | fixLogLevel(classLoader); 29 | generatePlayer(classLoader); 30 | player.startAudioOutput(); 31 | 32 | files.load(internalPlaylists); 33 | 34 | playListManager.setBasePath(files.getDirectory()); 35 | settingsManager.setBasePath(files.getDirectory()); 36 | 37 | playListManager.loadFromFile(); 38 | settingsManager.loadFromFile(); 39 | 40 | player.setVolume(settingsManager.getSettings().getVolume()); 41 | } 42 | 43 | private static void fixLogLevel(ClassLoader classLoader) { 44 | final String loggerName = "org.apache.http"; 45 | final LoggerContext context = ((LoggerContext) LogManager.getContext(classLoader, false)); 46 | context.getConfiguration().addLogger(loggerName, new LoggerConfig(loggerName, Level.INFO, true)); 47 | } 48 | 49 | private static void generatePlayer(ClassLoader classLoader) { 50 | try { 51 | final Class clazz = Class.forName("info.u_team.music_player.lavaplayer.MusicPlayer", true, classLoader); 52 | if (!IMusicPlayer.class.isAssignableFrom(clazz)) { 53 | throw new IllegalAccessError("The class " + clazz + " does not implement IMusicPlayer! This should not happen?!"); 54 | } 55 | player = (IMusicPlayer) clazz.getDeclaredConstructor().newInstance(); 56 | LOGGER.info("Successfully created music player instance"); 57 | } catch (final Exception ex) { 58 | LOGGER.fatal("Cannot create music player instance. This is a serious bug and the mod will not work. Report to the mod authors", ex); 59 | System.exit(-1); 60 | } 61 | } 62 | 63 | public static IMusicPlayer getPlayer() { 64 | return player; 65 | } 66 | 67 | public static MusicPlayerFiles getFiles() { 68 | return files; 69 | } 70 | 71 | public static PlaylistManager getPlaylistManager() { 72 | return playListManager; 73 | } 74 | 75 | public static SettingsManager getSettingsManager() { 76 | return settingsManager; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryFunctions.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.init.MusicPlayerResources; 4 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 5 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 6 | import info.u_team.music_player.musicplayer.playlist.Playlist; 7 | import info.u_team.music_player.musicplayer.playlist.Playlists; 8 | import info.u_team.music_player.util.WrappedObject; 9 | import info.u_team.u_team_core.gui.elements.ImageButton; 10 | import net.minecraft.client.gui.GuiGraphics; 11 | 12 | abstract class GuiMusicPlaylistListEntryFunctions extends GuiMusicPlaylistListEntryPlayable { 13 | 14 | protected final Playlist playlist; 15 | protected final WrappedObject uri; 16 | 17 | protected final ImageButton deleteTrackButton; 18 | protected final ImageButton upButton, downButton; 19 | 20 | GuiMusicPlaylistListEntryFunctions(GuiMusicPlaylistList guilist, Playlists playlists, Playlist playlist, LoadedTracks loadedTrack, IAudioTrack track) { 21 | super(playlists, playlist, loadedTrack, track); 22 | this.playlist = playlist; 23 | uri = loadedTrack.getUri(); 24 | deleteTrackButton = addChildren(new ImageButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_CLEAR)); 25 | upButton = addChildren(new ImageButton(0, 0, 20, 10, MusicPlayerResources.TEXTURE_UP)); 26 | downButton = addChildren(new ImageButton(0, 0, 20, 10, MusicPlayerResources.TEXTURE_DOWN)); 27 | 28 | deleteTrackButton.setPressable(() -> { 29 | playlist.remove(uri); 30 | guilist.updateAllEntries(); 31 | }); 32 | upButton.setPressable(() -> { 33 | playlist.move(uri, 1); 34 | 35 | guilist.setSelectedEntryWhenMove(this, -1); 36 | guilist.updateAllEntries(); 37 | }); 38 | downButton.setPressable(() -> { 39 | playlist.move(uri, -1); 40 | guilist.setSelectedEntryWhenMove(this, 1); 41 | guilist.updateAllEntries(); 42 | }); 43 | } 44 | 45 | @Override 46 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 47 | super.render(guiGraphics, slotIndex, entryY, entryX, entryWidth, entryHeight, mouseX, mouseY, hovered, partialTicks); 48 | drawEntryExtended(guiGraphics, entryX, entryY, entryWidth, entryHeight, mouseX, mouseY, hovered, partialTicks); 49 | 50 | deleteTrackButton.setX(entryWidth - 15); 51 | deleteTrackButton.setY(entryY + 8); 52 | deleteTrackButton.render(guiGraphics, mouseX, mouseY, partialTicks); 53 | 54 | upButton.setX(entryWidth - 40); 55 | upButton.setY(entryY + 8); 56 | upButton.render(guiGraphics, mouseX, mouseY, partialTicks); 57 | 58 | downButton.setX(entryWidth - 40); 59 | downButton.setY(entryY + 18); 60 | downButton.render(guiGraphics, mouseX, mouseY, partialTicks); 61 | } 62 | 63 | public abstract void drawEntryExtended(GuiGraphics guiGraphics, int entryX, int entryY, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean mouseInList, float partialTicks); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "fabric-loom" 3 | id "info.u_team.gradle_files" 4 | id "maven-publish" 5 | } 6 | 7 | gradlefiles.loaderSuffix = "common" 8 | 9 | group = rootProject.group 10 | base.archivesName = gradlefiles.archivesName() 11 | version = gradlefiles.version() 12 | 13 | sourceSets { 14 | common { 15 | java 16 | resources { 17 | srcDirs += "src/common_generated/resources" 18 | } 19 | compileClasspath = main.compileClasspath 20 | runtimeClasspath = main.runtimeClasspath 21 | } 22 | main { 23 | java { 24 | srcDirs += sourceSets.common.java.srcDirs 25 | } 26 | resources { 27 | srcDirs += sourceSets.common.resources.srcDirs 28 | } 29 | } 30 | } 31 | 32 | java { 33 | toolchain { 34 | languageVersion = JavaLanguageVersion.of(21) 35 | } 36 | withSourcesJar() 37 | withJavadocJar() 38 | } 39 | 40 | loom { 41 | accessWidenerPath = gradlefiles.project("fabric").file("src/main/resources/musicplayer.accesswidener") 42 | } 43 | 44 | tasks.withType(Jar).configureEach { task -> 45 | gradlefiles.defaultJar(task) 46 | 47 | manifest { 48 | attributes("Fabric-Loom-Remap": "true") 49 | } 50 | } 51 | 52 | tasks.withType(Javadoc).configureEach { task -> 53 | task.options.addStringOption("Xdoclint:none", "-quiet") 54 | } 55 | 56 | signjar.sign(tasks.named("remapJar")) 57 | 58 | processResources { 59 | doLast { 60 | fileTree(dir: outputs.files.asPath, include: "**/*.json").each { File file -> 61 | file.text = groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parse(file)) 62 | } 63 | } 64 | } 65 | 66 | repositories { 67 | maven { 68 | url = "https://maven.fabricmc.net" 69 | } 70 | maven { 71 | url = "https://maven.parchmentmc.org" 72 | } 73 | maven { 74 | url = "https://repo.u-team.info" 75 | } 76 | mavenCentral() 77 | } 78 | 79 | dependencies { 80 | minecraft gradlefiles.fabricMinecraftDependency() 81 | mappings loom.layered() { 82 | officialMojangMappings() 83 | parchment(config.fabric.mapping_layer) 84 | } 85 | 86 | modImplementation gradlefiles.fabricLoaderDependency() 87 | modRuntimeOnly gradlefiles.fabricApiDependency() 88 | 89 | modImplementation "info.u-team:u_team_core-common-1.21.1:5.6.2.384" 90 | 91 | compileOnly project(":musicplayer-lavaplayer-api") 92 | compileOnly ("net.harawata:appdirs:1.4.0") { 93 | transitive=false 94 | } 95 | } 96 | 97 | publishing { 98 | repositories { 99 | maven { 100 | url = "https://repo.u-team.info" 101 | credentials { 102 | username = "maven" 103 | password = defaultPropertyValue("maven.password") 104 | } 105 | } 106 | } 107 | publications { 108 | mavenJava(MavenPublication) { 109 | artifactId = project.base.archivesName.get() 110 | 111 | from gradlefiles.filteredJavaComponent { 112 | filterDependency { holder -> 113 | "appdirs" == holder.dependency.name 114 | } 115 | filterDependency { holder -> 116 | "musicplayer-lavaplayer-api" == holder.dependency.name 117 | } 118 | } 119 | 120 | pom { 121 | pom.name = project.base.archivesName.get() 122 | rootProject.commonPom(it) 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistList.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import info.u_team.music_player.gui.BetterScrollableList; 7 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 8 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 9 | import info.u_team.music_player.musicplayer.playlist.Playlist; 10 | import info.u_team.music_player.musicplayer.playlist.Playlists; 11 | 12 | public class GuiMusicPlaylistList extends BetterScrollableList { 13 | 14 | private final Playlist playlist; 15 | 16 | private boolean tracksLoaded; 17 | 18 | private int selectIndex; 19 | 20 | public GuiMusicPlaylistList(Playlist playlist) { 21 | super(0, 0, 0, 0, 40, 20); 22 | this.playlist = playlist; 23 | addEntry(new GuiMusicPlaylistListEntryLoading()); 24 | } 25 | 26 | private void addLoadedTrackToGui(LoadedTracks loadedTracks) { 27 | final Playlists playlists = MusicPlayerManager.getPlaylistManager().getPlaylists(); 28 | final List list = new ArrayList<>(); 29 | if (loadedTracks.hasError()) {// Add error gui element 30 | list.add(new GuiMusicPlaylistListEntryError(this, playlists, playlist, loadedTracks, loadedTracks.getErrorMessage())); 31 | } else if (loadedTracks.isTrack()) { // Add track gui element 32 | list.add(new GuiMusicPlaylistListEntryMusicTrack(this, playlists, playlist, loadedTracks)); 33 | } else if (loadedTracks.isTrackList()) { // Add playlist start element and all track sub elements 34 | final GuiMusicPlaylistListEntryPlaylistStart start = new GuiMusicPlaylistListEntryPlaylistStart(this, playlists, playlist, loadedTracks); 35 | list.add(start); 36 | loadedTracks.getTrackList().getTracks().forEach(track -> { 37 | final GuiMusicPlaylistListEntryPlaylistTrack entry = new GuiMusicPlaylistListEntryPlaylistTrack(start, playlists, playlist, loadedTracks, track); 38 | start.addEntry(entry); 39 | list.add(entry); 40 | }); 41 | } 42 | list.forEach(this::addEntry); 43 | } 44 | 45 | public void addAllEntries() { 46 | if (!playlist.isLoaded()) { 47 | return; 48 | } 49 | if (!tracksLoaded) { 50 | clearEntries(); 51 | playlist.getLoadedTracks().forEach(this::addLoadedTrackToGui); 52 | tracksLoaded = true; 53 | } 54 | } 55 | 56 | public void removeAllEntries() { 57 | clearEntries(); 58 | tracksLoaded = false; 59 | } 60 | 61 | public void updateAllEntries() { 62 | removeAllEntries(); 63 | addAllEntries(); 64 | } 65 | 66 | public void setSelectedEntryWhenMove(GuiMusicPlaylistListEntry entry, int indexOffset) { 67 | final int index = children().lastIndexOf(entry) + indexOffset; 68 | if (index >= 0 && index < children().size()) { 69 | selectIndex = index; 70 | } 71 | } 72 | 73 | @Override 74 | protected boolean isSelectedItem(int index) { 75 | return index == selectIndex; 76 | } 77 | 78 | @Override 79 | public void setSelected(GuiMusicPlaylistListEntry entry) { 80 | if (entry != null) { 81 | selectIndex = children().indexOf(entry); 82 | } 83 | super.setSelected(entry); 84 | } 85 | 86 | public void tick() { 87 | children().forEach(GuiMusicPlaylistListEntry::tick); 88 | } 89 | } -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/musicplayer/playlist/LoadedTracks.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.musicplayer.playlist; 2 | 3 | import java.util.List; 4 | 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackList; 7 | import info.u_team.music_player.lavaplayer.api.search.ISearchResult; 8 | import info.u_team.music_player.util.WrappedObject; 9 | 10 | public class LoadedTracks { 11 | 12 | private final WrappedObject uri; 13 | 14 | private String errorMessage; 15 | 16 | private String title; 17 | private IAudioTrack track; 18 | private IAudioTrackList trackList; 19 | 20 | /** 21 | * Dummy 22 | * 23 | * @param uri 24 | */ 25 | public LoadedTracks(WrappedObject uri) { 26 | this.uri = uri; 27 | errorMessage = "Not loaded yet"; 28 | } 29 | 30 | public LoadedTracks(WrappedObject uri, ISearchResult result) { 31 | this.uri = uri; 32 | if (result.hasError()) { 33 | errorMessage = result.getErrorMessage(); 34 | } else { 35 | if (!result.isList()) { 36 | track = result.getTrack(); 37 | title = track.getInfo().getTitle(); 38 | } else { 39 | trackList = result.getTrackList(); 40 | title = trackList.getName(); 41 | } 42 | } 43 | } 44 | 45 | public LoadedTracks(WrappedObject uri, IAudioTrack track) { 46 | this.uri = uri; 47 | this.track = track; 48 | title = track.getInfo().getTitle(); 49 | } 50 | 51 | public LoadedTracks(WrappedObject uri, IAudioTrackList trackList) { 52 | this.uri = uri; 53 | this.trackList = trackList; 54 | title = trackList.getName(); 55 | } 56 | 57 | public WrappedObject getUri() { 58 | return uri; 59 | } 60 | 61 | public boolean hasError() { 62 | return errorMessage != null; 63 | } 64 | 65 | public String getErrorMessage() { 66 | return errorMessage; 67 | } 68 | 69 | public String getTitle() { 70 | return title; 71 | } 72 | 73 | public boolean isTrack() { 74 | return trackList == null && track != null; 75 | } 76 | 77 | public boolean isTrackList() { 78 | return trackList != null && track == null; 79 | } 80 | 81 | public IAudioTrack getTrack() { 82 | return track; 83 | } 84 | 85 | public IAudioTrackList getTrackList() { 86 | return trackList; 87 | } 88 | 89 | public IAudioTrack getFirstTrack() { 90 | if (isTrack()) { 91 | return track; 92 | } else if (isTrackList()) { 93 | return trackList.getTracks().get(0); 94 | } 95 | return null; 96 | } 97 | 98 | public IAudioTrack getLastTrack() { 99 | if (isTrack()) { 100 | return track; 101 | } else if (isTrackList()) { 102 | return trackList.getTracks().get(trackList.getTracks().size() - 1); 103 | } 104 | return null; 105 | } 106 | 107 | public IAudioTrack getOtherTrack(IAudioTrack track, Skip skip) { 108 | if (isTrack() || !isTrackList()) { 109 | return null; 110 | } 111 | final List list = trackList.getTracks(); 112 | final int index = list.indexOf(track); 113 | final int newIndex = index + skip.getValue(); 114 | if (newIndex >= 0 && newIndex < list.size()) { 115 | return list.get(newIndex); 116 | } 117 | return null; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/init/MusicPlayerLocalization.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.init; 2 | 3 | import net.minecraft.client.resources.language.I18n; 4 | 5 | public class MusicPlayerLocalization { 6 | 7 | // Keys 8 | public static final String KEY_CATEGORY = "key.musicplayer.category"; 9 | public static final String KEY_OPEN = "key.musicplayer.open"; 10 | public static final String KEY_PAUSE = "key.musicplayer.pause"; 11 | public static final String KEY_SKIP_FORWARD = "key.musicplayer.skip.forward"; 12 | public static final String KEY_SKIP_BACK = "key.musicplayer.skip.back"; 13 | 14 | // Guis 15 | public static final String GUI_CREATE_PLAYLIST_INSERT_NAME = "gui.musicplayer.create_playlist.insert_name"; 16 | public static final String GUI_CREATE_PLAYLIST_ADD_LIST = "gui.musicplayer.create_playlist.add_list"; 17 | 18 | public static final String GUI_PLAYLISTS_NO_NAME = "gui.musicplayer.playlists.no_name"; 19 | public static final String GUI_PLAYLISTS_ENTRY = "gui.musicplayer.playlists.entry"; 20 | public static final String GUI_PLAYLISTS_ENTRIES = "gui.musicplayer.playlists.entries"; 21 | 22 | public static final String GUI_CONTROLS_VOLUME = "gui.controls.volume"; 23 | 24 | public static final String GUI_PLAYLIST_LOADING = "gui.playlist.loading"; 25 | 26 | public static final String GUI_TRACK_DURATION_UNDEFINED = "gui.track.duration_undefined"; 27 | 28 | public static final String GUI_SEARCH_HEADER = "gui.search.header"; 29 | public static final String GUI_SEARCH_LOAD_FILE = "gui.search.load.file"; 30 | public static final String GUI_SEARCH_LOAD_FOLDER = "gui.search.load.folder"; 31 | public static final String GUI_SEARCH_MUSIC_FILES = "gui.search.music_files"; 32 | public static final String GUI_SEARCH_ADD_ALL = "gui.search.add_all"; 33 | public static final String GUI_SEARCH_ADDED = "gui.search.added"; 34 | public static final String GUI_SEARCH_ADDED_LIST = "gui.search.added_list"; 35 | public static final String GUI_SEARCH_ADDED_ALL = "gui.search.added_all"; 36 | public static final String GUI_SEARCH_SEARCH_URI = "gui.search.search.uri"; 37 | public static final String GUI_SEARCH_SEARCH_FILE = "gui.search.search.file"; 38 | public static final String GUI_SEARCH_SEARCH_SEARCH = "gui.search.search.search"; 39 | 40 | public static final String GUI_SETTINGS_TOGGLE_INGAME_OVERLAY = "gui.settings.toggle.ingame_overlay"; 41 | public static final String GUI_SETTINGS_TOGGLE_MENUE_OVERLAY = "gui.settings.toggle.menue_overlay"; 42 | public static final String GUI_SETTINGS_TOGGLE_KEY_IN_GUI = "gui.settings.toggle.key_in_gui"; 43 | public static final String GUI_SETTINGS_POSITION_OVERLAY = "gui.settings.position.overlay"; 44 | public static final String GUI_SETTINGS_POSITION_UP_LEFT = "gui.settings.position.up_left"; 45 | public static final String GUI_SETTINGS_POSITION_UP_RIGHT = "gui.settings.position.up_right"; 46 | public static final String GUI_SETTINGS_POSITION_DOWN_RIGHT = "gui.settings.position.down_right"; 47 | public static final String GUI_SETTINGS_POSITION_DOWN_LEFT = "gui.settings.position.down_left"; 48 | public static final String GUI_SETTINGS_SPEED = "gui.settings.speed"; 49 | public static final String GUI_SETTINGS_PITCH = "gui.settings.pitch"; 50 | public static final String GUI_SETTINGS_MIXER_DEVICE_SELECTION = "gui.settings.mixer_device_selection"; 51 | 52 | public static String getTranslation(String key, Object... parameters) { 53 | return I18n.get(key, parameters); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/sources/AudioSources.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.sources; 2 | 3 | import java.util.function.Supplier; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import com.github.topi314.lavasrc.spotify.SpotifySourceManager; 9 | import com.sedmelluq.discord.lavaplayer.player.AudioPlayerManager; 10 | import com.sedmelluq.discord.lavaplayer.source.AudioSourceManager; 11 | import com.sedmelluq.discord.lavaplayer.source.bandcamp.BandcampAudioSourceManager; 12 | import com.sedmelluq.discord.lavaplayer.source.getyarn.GetyarnAudioSourceManager; 13 | import com.sedmelluq.discord.lavaplayer.source.http.HttpAudioSourceManager; 14 | import com.sedmelluq.discord.lavaplayer.source.local.LocalAudioSourceManager; 15 | import com.sedmelluq.discord.lavaplayer.source.nico.NicoAudioSourceManager; 16 | import com.sedmelluq.discord.lavaplayer.source.soundcloud.SoundCloudAudioSourceManager; 17 | import com.sedmelluq.discord.lavaplayer.source.twitch.TwitchStreamAudioSourceManager; 18 | import com.sedmelluq.discord.lavaplayer.source.vimeo.VimeoAudioSourceManager; 19 | import com.sedmelluq.discord.lavaplayer.source.yamusic.YandexMusicAudioSourceManager; 20 | 21 | import dev.lavalink.youtube.YoutubeAudioSourceManager; 22 | 23 | public class AudioSources { 24 | 25 | private static final Logger LOGGER = LoggerFactory.getLogger(AudioSources.class); 26 | 27 | public static void registerSources(AudioPlayerManager audioPlayerManager) { 28 | registerManager(audioPlayerManager, () -> { 29 | final YoutubeAudioSourceManager youtube = new YoutubeAudioSourceManager(); 30 | youtube.setPlaylistPageCount(100); 31 | return youtube; 32 | }); 33 | registerManager(audioPlayerManager, SoundCloudAudioSourceManager::createDefault); 34 | registerManager(audioPlayerManager, () -> { 35 | final String clientId = System.getProperty("musicplayer.lavaplayer.spotify.clientId"); 36 | final String clientSecret = System.getProperty("musicplayer.lavaplayer.spotify.clientSecret"); 37 | if (clientId != null && clientSecret != null) { 38 | return new SpotifySourceManager(null, clientId, clientSecret, "", audioPlayerManager); 39 | } 40 | return null; 41 | }); 42 | registerManager(audioPlayerManager, BandcampAudioSourceManager::new); 43 | registerManager(audioPlayerManager, VimeoAudioSourceManager::new); 44 | registerManager(audioPlayerManager, TwitchStreamAudioSourceManager::new); 45 | registerManager(audioPlayerManager, GetyarnAudioSourceManager::new); 46 | registerManager(audioPlayerManager, NicoAudioSourceManager::new); 47 | registerManager(audioPlayerManager, YandexMusicAudioSourceManager::new); 48 | registerManager(audioPlayerManager, HttpAudioSourceManager::new); 49 | registerManager(audioPlayerManager, LocalAudioSourceManager::new); 50 | } 51 | 52 | private static void registerManager(AudioPlayerManager audioPlayerManager, Supplier audioSourceManager) { 53 | try { 54 | final AudioSourceManager manager = audioSourceManager.get(); 55 | if (manager != null) { 56 | LOGGER.info("Register {} source manager for music player", manager.getSourceName()); 57 | audioPlayerManager.registerSourceManager(manager); 58 | } 59 | } catch (final Exception ex) { 60 | LOGGER.warn("Cannot register source manager. Some music tracks might not be playable. Most often it is caused by an unstable internet connection or blocked services", ex); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/util/GuiTrackUtils.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.util; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_TRACK_DURATION_UNDEFINED; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 5 | 6 | import java.net.URI; 7 | import java.util.function.Function; 8 | 9 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 10 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrackInfo; 11 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 12 | import info.u_team.music_player.util.TimeUtil; 13 | import net.minecraft.client.Minecraft; 14 | import net.minecraft.client.gui.GuiGraphics; 15 | import net.minecraft.network.chat.ClickEvent; 16 | import net.minecraft.network.chat.ClickEvent.Action; 17 | import net.minecraft.network.chat.Component; 18 | import net.minecraft.network.chat.Style; 19 | 20 | public final class GuiTrackUtils { 21 | 22 | private static final Minecraft MINECRAFT = Minecraft.getInstance(); 23 | 24 | public static String trimToWith(String string, int width) { 25 | String newString = MINECRAFT.font.plainSubstrByWidth(string, width); 26 | if (!newString.equals(string)) { 27 | newString += "..."; 28 | } 29 | return newString; 30 | } 31 | 32 | public static void addTrackInfo(GuiGraphics guiGraphics, IAudioTrack track, int x, int y, int entryWidth, int leftMargin, int titleColor) { 33 | final int textSize = entryWidth - 150 - leftMargin; 34 | 35 | final IAudioTrackInfo info = track.getInfo(); 36 | 37 | final String title = trimToWith(info.getFixedTitle(), textSize); 38 | final String author = trimToWith(info.getFixedAuthor(), textSize); 39 | final String duration = getFormattedDuration(track); 40 | 41 | guiGraphics.drawString(MINECRAFT.font, title, x + leftMargin, y + 5, titleColor, false); 42 | guiGraphics.drawString(MINECRAFT.font, author, x + leftMargin + 4, y + 25, 0xD86D1C, false); 43 | guiGraphics.drawString(MINECRAFT.font, duration, x + entryWidth - 140, y + 15, 0xFFFF00, false); 44 | } 45 | 46 | public static boolean openURI(String uri) { 47 | Style style = Component.nullToEmpty(null).getStyle(); 48 | try { 49 | new URI(uri); 50 | style = style.withClickEvent(new ClickEvent(Action.OPEN_URL, uri)); 51 | } catch (final Exception ex) { 52 | style = style.withClickEvent(new ClickEvent(Action.OPEN_FILE, uri)); 53 | } 54 | return MINECRAFT.screen.handleComponentClicked(style); 55 | } 56 | 57 | public static String getFormattedDuration(IAudioTrack track) { 58 | final long seconds; 59 | if (track == null) { 60 | seconds = 0; 61 | } else { 62 | final IAudioTrackInfo info = track.getInfo(); 63 | if (info.isStream()) { 64 | return getTranslation(GUI_TRACK_DURATION_UNDEFINED); 65 | } 66 | seconds = track.getDuration() / 1000; 67 | } 68 | return TimeUtil.timeConversion(seconds); 69 | } 70 | 71 | public static String getFormattedPosition(IAudioTrack track) { 72 | return TimeUtil.timeConversion(track == null ? 0 : track.getPosition() / 1000); 73 | } 74 | 75 | public static T getValueOfPlayingTrack(Function function) { 76 | return getValueOfNullableTrack(MusicPlayerManager.getPlayer().getTrackManager().getCurrentTrack(), function); 77 | } 78 | 79 | public static T getValueOfNullableTrack(IAudioTrack track, Function function) { 80 | if (track != null) { 81 | return function.apply(track); 82 | } 83 | return null; 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylist.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.gui.BetterScreen; 4 | import info.u_team.music_player.gui.GuiMusicPlayer; 5 | import info.u_team.music_player.gui.controls.GuiControls; 6 | import info.u_team.music_player.gui.playlist.search.GuiMusicSearch; 7 | import info.u_team.music_player.init.MusicPlayerResources; 8 | import info.u_team.music_player.musicplayer.playlist.Playlist; 9 | import info.u_team.u_team_core.gui.elements.ImageButton; 10 | import info.u_team.u_team_core.gui.elements.ScrollingText; 11 | import net.minecraft.client.Minecraft; 12 | import net.minecraft.client.gui.GuiGraphics; 13 | import net.minecraft.network.chat.Component; 14 | 15 | public class GuiMusicPlaylist extends BetterScreen { 16 | 17 | private final Playlist playlist; 18 | 19 | private final GuiMusicPlaylistList trackList; 20 | 21 | private ImageButton addTracksButton; 22 | 23 | private GuiControls controls; 24 | 25 | public GuiMusicPlaylist(Playlist playlist) { 26 | super(Component.literal("musicplaylist")); 27 | this.playlist = playlist; 28 | 29 | trackList = new GuiMusicPlaylistList(playlist); 30 | 31 | if (!playlist.isLoaded()) { 32 | playlist.load(() -> { 33 | if (Minecraft.getInstance().screen == this) { // Check if gui is still open 34 | Minecraft.getInstance().execute(() -> { 35 | if (Minecraft.getInstance().screen == this) { // Recheck gui because this is async on the main thread. 36 | trackList.addAllEntries(); 37 | if (addTracksButton != null) { 38 | addTracksButton.active = true; 39 | } 40 | } 41 | }); 42 | } 43 | }); 44 | } 45 | } 46 | 47 | @Override 48 | protected void init() { 49 | final ImageButton backButton = addRenderableWidget(new ImageButton(1, 1, 15, 15, MusicPlayerResources.TEXTURE_BACK)); 50 | backButton.setPressable(() -> minecraft.setScreen(new GuiMusicPlayer())); 51 | 52 | addTracksButton = addRenderableWidget(new ImageButton(width - 35, 20, 22, 22, MusicPlayerResources.TEXTURE_ADD)); 53 | addTracksButton.setPressable(() -> minecraft.setScreen(new GuiMusicSearch(playlist))); 54 | 55 | if (!playlist.isLoaded()) { 56 | addTracksButton.active = false; 57 | } 58 | 59 | trackList.updateSettings(12, 50, width - 24, height - 60); 60 | trackList.addAllEntries(); 61 | addWidget(trackList); 62 | 63 | controls = new GuiControls(this, 5, width); 64 | addWidget(controls); 65 | } 66 | 67 | @Override 68 | public void tick() { 69 | controls.tick(); 70 | trackList.tick(); 71 | } 72 | 73 | @Override 74 | public void resize(Minecraft minecraft, int width, int height) { 75 | final ScrollingText titleRender = controls.getTitleRender(); 76 | final ScrollingText authorRender = controls.getAuthorRender(); 77 | this.init(minecraft, width, height); 78 | controls.copyTitleRendererState(titleRender); 79 | controls.copyAuthorRendererState(authorRender); 80 | } 81 | 82 | @Override 83 | public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 84 | super.render(guiGraphics, mouseX, mouseY, partialTicks); 85 | trackList.render(guiGraphics, mouseX, mouseY, partialTicks); 86 | controls.render(guiGraphics, mouseX, mouseY, partialTicks); 87 | } 88 | 89 | @Override 90 | public void renderBackground(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 91 | super.renderBackground(guiGraphics, mouseX, mouseY, partialTicks); 92 | } 93 | 94 | public GuiMusicPlaylistList getTrackList() { 95 | return trackList; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/render/RenderOverlayMusicDisplay.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.render; 2 | 3 | import info.u_team.music_player.gui.util.GuiTrackUtils; 4 | import info.u_team.music_player.init.MusicPlayerColors; 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 7 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 8 | import info.u_team.u_team_core.gui.elements.ScalableText; 9 | import info.u_team.u_team_core.gui.elements.ScrollingText; 10 | import net.minecraft.client.Minecraft; 11 | import net.minecraft.client.gui.Font; 12 | import net.minecraft.client.gui.GuiGraphics; 13 | import net.minecraft.client.gui.components.Renderable; 14 | 15 | public class RenderOverlayMusicDisplay implements Renderable { 16 | 17 | private final ITrackManager manager; 18 | 19 | private final int width; 20 | private final int height; 21 | 22 | private final ScrollingText title; 23 | private final ScrollingText author; 24 | 25 | private final ScalableText position; 26 | private final ScalableText duration; 27 | 28 | public RenderOverlayMusicDisplay() { 29 | manager = MusicPlayerManager.getPlayer().getTrackManager(); 30 | 31 | height = 35; 32 | width = 120; 33 | 34 | final Font fontRender = Minecraft.getInstance().font; 35 | 36 | title = new ScrollingText(fontRender, () -> GuiTrackUtils.getValueOfPlayingTrack(track -> track.getInfo().getFixedTitle()), 3, 2); 37 | title.setStepSize(0.5F); 38 | title.setColor(MusicPlayerColors.YELLOW); 39 | title.setWidth(114); 40 | title.setSpeedTime(35); 41 | 42 | author = new ScrollingText(fontRender, () -> GuiTrackUtils.getValueOfPlayingTrack(track -> track.getInfo().getFixedAuthor()), 3, 12); 43 | author.setStepSize(0.5F); 44 | author.setColor(MusicPlayerColors.YELLOW); 45 | author.setScale(0.75F); 46 | author.setWidth(114); 47 | author.setSpeedTime(35); 48 | 49 | position = new ScalableText(fontRender, () -> GuiTrackUtils.getValueOfPlayingTrack(GuiTrackUtils::getFormattedPosition), 6, 28); 50 | position.setColor(MusicPlayerColors.YELLOW); 51 | position.setScale(0.5F); 52 | 53 | duration = new ScalableText(fontRender, () -> GuiTrackUtils.getValueOfPlayingTrack(GuiTrackUtils::getFormattedDuration), width - 6, 28); 54 | duration.setTextChanged(renderer -> { 55 | duration.setX(width - 6 - renderer.getTextWidth()); 56 | }); 57 | duration.setColor(MusicPlayerColors.YELLOW); 58 | duration.setScale(0.5F); 59 | 60 | } 61 | 62 | @Override 63 | public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 64 | final IAudioTrack track = manager.getCurrentTrack(); 65 | if (track == null) { 66 | return; 67 | } 68 | // Background 69 | guiGraphics.fill(0, 0, width, height, 0xFF212121); 70 | 71 | // Progressbar 72 | final double progress; 73 | if (track.getInfo().isStream()) { 74 | progress = 0.5; 75 | } else { 76 | progress = (double) track.getPosition() / track.getDuration(); 77 | } 78 | 79 | guiGraphics.fill(6, 23, width - 6, 26, 0xFF555555); 80 | guiGraphics.fill(6, 23, 6 + (int) ((width - 12) * progress), 26, 0xFF3E9100); 81 | 82 | // Draw strings 83 | title.render(guiGraphics, mouseX, mouseY, partialTicks); 84 | author.render(guiGraphics, mouseX, mouseY, partialTicks); 85 | 86 | position.render(guiGraphics, mouseX, mouseY, partialTicks); 87 | duration.render(guiGraphics, mouseX, mouseY, partialTicks); 88 | } 89 | 90 | public int getWidth() { 91 | return width; 92 | } 93 | 94 | public int getHeight() { 95 | return height; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/GuiMusicPlayer.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_CREATE_PLAYLIST_ADD_LIST; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_CREATE_PLAYLIST_INSERT_NAME; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 6 | 7 | import org.apache.commons.lang3.StringUtils; 8 | 9 | import info.u_team.music_player.gui.controls.GuiControls; 10 | import info.u_team.music_player.init.MusicPlayerResources; 11 | import info.u_team.u_team_core.gui.elements.ImageButton; 12 | import info.u_team.u_team_core.gui.elements.ScrollingText; 13 | import net.minecraft.client.Minecraft; 14 | import net.minecraft.client.gui.GuiGraphics; 15 | import net.minecraft.client.gui.components.EditBox; 16 | import net.minecraft.network.chat.Component; 17 | 18 | public class GuiMusicPlayer extends BetterScreen { 19 | 20 | private EditBox namePlaylistField; 21 | 22 | private GuiMusicPlayerList playlistsList; 23 | 24 | private GuiControls controls; 25 | 26 | public GuiMusicPlayer() { 27 | super(Component.literal("musicplayer")); 28 | } 29 | 30 | @Override 31 | protected void init() { 32 | addRenderableWidget(new ImageButton(1, 1, 15, 15, MusicPlayerResources.TEXTURE_BACK, button -> minecraft.setScreen(null))); 33 | 34 | namePlaylistField = new EditBox(font, 100, 60, width - 150, 20, Component.nullToEmpty(null)); 35 | namePlaylistField.setMaxLength(500); 36 | addWidget(namePlaylistField); 37 | 38 | final ImageButton addPlaylistButton = addRenderableWidget(new ImageButton(width - 41, 59, 22, 22, MusicPlayerResources.TEXTURE_CREATE)); 39 | addPlaylistButton.setPressable(() -> { 40 | final String name = namePlaylistField.getValue(); 41 | if (StringUtils.isBlank(name) || name.equals(getTranslation(GUI_CREATE_PLAYLIST_INSERT_NAME))) { 42 | namePlaylistField.setValue(getTranslation(GUI_CREATE_PLAYLIST_INSERT_NAME)); 43 | return; 44 | } 45 | playlistsList.addPlaylist(name); 46 | namePlaylistField.setValue(""); 47 | }); 48 | 49 | playlistsList = new GuiMusicPlayerList(12, 90, width - 24, height - 100); 50 | addWidget(playlistsList); 51 | 52 | controls = new GuiControls(this, 5, width); 53 | addWidget(controls); 54 | } 55 | 56 | @Override 57 | public void resize(Minecraft minecraft, int width, int height) { 58 | final String text = namePlaylistField.getValue(); 59 | final ScrollingText titleRender = controls.getTitleRender(); 60 | final ScrollingText authorRender = controls.getAuthorRender(); 61 | this.init(minecraft, width, height); 62 | namePlaylistField.setValue(text); 63 | controls.copyTitleRendererState(titleRender); 64 | controls.copyAuthorRendererState(authorRender); 65 | } 66 | 67 | @Override 68 | public void tick() { 69 | controls.tick(); 70 | } 71 | 72 | @Override 73 | public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 74 | super.render(guiGraphics, mouseX, mouseY, partialTicks); 75 | playlistsList.render(guiGraphics, mouseX, mouseY, partialTicks); 76 | guiGraphics.drawString(font, getTranslation(GUI_CREATE_PLAYLIST_ADD_LIST), 20, 65, 0xFFFFFF, false); 77 | namePlaylistField.render(guiGraphics, mouseX, mouseY, partialTicks); 78 | controls.render(guiGraphics, mouseX, mouseY, partialTicks); 79 | } 80 | 81 | @Override 82 | public void renderBackground(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTicks) { 83 | super.renderBackground(guiGraphics, mouseX, mouseY, partialTicks); 84 | } 85 | 86 | public GuiMusicPlayerList getPlaylistsList() { 87 | return playlistsList; 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/playlist/GuiMusicPlaylistListEntryPlayable.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui.playlist; 2 | 3 | import info.u_team.music_player.gui.util.GuiTrackUtils; 4 | import info.u_team.music_player.init.MusicPlayerResources; 5 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 6 | import info.u_team.music_player.lavaplayer.api.audio.IPlayingTrack; 7 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 8 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 9 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 10 | import info.u_team.music_player.musicplayer.playlist.Playlist; 11 | import info.u_team.music_player.musicplayer.playlist.Playlists; 12 | import info.u_team.u_team_core.gui.elements.ImageToggleButton; 13 | import net.minecraft.client.gui.GuiGraphics; 14 | 15 | public abstract class GuiMusicPlaylistListEntryPlayable extends GuiMusicPlaylistListEntry { 16 | 17 | private final ITrackManager manager; 18 | private final IAudioTrack track; 19 | 20 | private final LoadedTracks loadedTrack; 21 | 22 | protected final ImageToggleButton playTrackButton; 23 | 24 | GuiMusicPlaylistListEntryPlayable(Playlists playlists, Playlist playlist, LoadedTracks loadedTrack, IAudioTrack track) { 25 | this.track = track; 26 | this.loadedTrack = loadedTrack; 27 | manager = MusicPlayerManager.getPlayer().getTrackManager(); 28 | 29 | playTrackButton = addChildren(new ImageToggleButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_PLAY, MusicPlayerResources.TEXTURE_PAUSE, false)); 30 | 31 | if (loadedTrack.hasError() || track == null) { 32 | playTrackButton.visible = false; 33 | } else { 34 | playTrackButton.setToggled(track == getCurrentlyPlaying()); 35 | playTrackButton.setPressable(() -> { 36 | final boolean play = playTrackButton.isToggled(); 37 | if (play) { 38 | if (manager.isPaused() && getCurrentlyPlaying() == track) { 39 | manager.setPaused(false); 40 | } else { 41 | playlists.setPlaying(playlist); 42 | playlist.setPlayable(loadedTrack, track); 43 | manager.setTrackQueue(playlist); 44 | manager.start(); 45 | } 46 | } else { 47 | manager.setPaused(true); 48 | } 49 | }); 50 | } 51 | } 52 | 53 | @Override 54 | public boolean mouseClicked(double mouseX, double mouseY, int button) { 55 | if (button == 2) { 56 | final String uri = this instanceof GuiMusicPlaylistListEntryPlaylistStart || this instanceof GuiMusicPlaylistListEntryError ? loadedTrack.getUri().get() : track.getInfo().getURI(); 57 | if (GuiTrackUtils.openURI(uri)) { 58 | return true; 59 | } 60 | } 61 | return super.mouseClicked(mouseX, mouseY, button); 62 | } 63 | 64 | @Override 65 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 66 | playTrackButton.setX(entryWidth - 65); 67 | playTrackButton.setY(entryY + 8); 68 | playTrackButton.render(guiGraphics, mouseX, mouseY, partialTicks); 69 | } 70 | 71 | @Override 72 | protected void tick() { 73 | if (isPlaying()) { 74 | playTrackButton.setToggled(!manager.isPaused()); 75 | } else { 76 | playTrackButton.setToggled(false); 77 | } 78 | } 79 | 80 | protected IAudioTrack getCurrentlyPlaying() { 81 | final IPlayingTrack track = manager.getCurrentTrack(); 82 | return track == null ? null : track.getOriginalTrack(); 83 | } 84 | 85 | protected boolean isPlaying() { 86 | return getCurrentlyPlaying() == track; 87 | } 88 | 89 | public IAudioTrack getTrack() { 90 | return track; 91 | } 92 | 93 | public ImageToggleButton getPlayTrackButton() { 94 | return playTrackButton; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/test_player/java/info/u_team/music_player/lavaplayer/testimpl/Main.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.lavaplayer.testimpl; 2 | 3 | import java.time.Instant; 4 | import java.time.ZoneId; 5 | import java.time.format.DateTimeFormatter; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | import java.util.Random; 9 | import java.util.Scanner; 10 | import java.util.concurrent.Executors; 11 | import java.util.concurrent.TimeUnit; 12 | import java.util.concurrent.atomic.AtomicInteger; 13 | 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | import info.u_team.music_player.lavaplayer.MusicPlayer; 18 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 19 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 20 | import info.u_team.music_player.lavaplayer.api.queue.ITrackQueue; 21 | 22 | public class Main { 23 | 24 | private final Logger log = LoggerFactory.getLogger(Main.class); 25 | 26 | public static void main(String[] args) { 27 | new Main(); 28 | } 29 | 30 | public Main() { 31 | final MusicPlayer musicPlayer = new MusicPlayer(); 32 | musicPlayer.startAudioOutput(); 33 | 34 | musicPlayer.setVolume(10); 35 | 36 | final ITrackManager manager = musicPlayer.getTrackManager(); 37 | 38 | musicPlayer.getTrackSearch().getTracks("https://www.youtube.com/playlist?list=PLyseegEZ84-drkYTkLldkiIBPHRJd7Xgd", result -> { 39 | if (result.isList()) { 40 | manager.setTrackQueue(new TrackQueue(result.getTrackList().getTracks())); 41 | } else { 42 | manager.setTrackQueue(new TrackQueue(Arrays.asList(result.getTrack()))); 43 | } 44 | log.info("Loaded all tracks -> starting now"); 45 | manager.start(); 46 | }); 47 | 48 | new Thread(() -> { 49 | final Scanner scanner = new Scanner(System.in); 50 | while (scanner.hasNext()) { 51 | final String line = scanner.nextLine(); 52 | if (line.startsWith("pause")) { 53 | manager.setPaused(true); 54 | } else if (line.startsWith("unpause")) { 55 | manager.setPaused(false); 56 | } else if (line.startsWith("skip")) { 57 | manager.skip(); 58 | } else if (line.startsWith("rate")) { 59 | final IAudioTrack audioTrack = manager.getCurrentTrack(); 60 | System.out.println((float) audioTrack.getPosition() / audioTrack.getDuration()); 61 | } else if (line.startsWith("speed")) { 62 | try { 63 | musicPlayer.setSpeed(Float.parseFloat(line.substring("speed ".length()))); 64 | } catch (NumberFormatException ex) { 65 | } 66 | } else if (line.startsWith("pitch")) { 67 | try { 68 | musicPlayer.setPitch(Float.parseFloat(line.substring("pitch ".length()))); 69 | } catch (NumberFormatException ex) { 70 | } 71 | } else if (line.startsWith("stop")) { 72 | manager.stop(); 73 | System.exit(0); 74 | } else if (line.startsWith("setending")) { 75 | final IAudioTrack audioTrack = manager.getCurrentTrack(); 76 | audioTrack.setPosition(audioTrack.getDuration() - 10000); 77 | } else if (line.startsWith("playing")) { 78 | final IAudioTrack audioTrack = manager.getCurrentTrack(); 79 | System.out.println(audioTrack.getInfo().getAuthor() + " - " + audioTrack.getInfo().getTitle()); 80 | } 81 | } 82 | scanner.close(); 83 | }, "Music player manager").start(); 84 | 85 | final AtomicInteger counter = new AtomicInteger(); 86 | final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.systemDefault()); 87 | Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> { 88 | final IAudioTrack audioTrack = manager.getCurrentTrack(); 89 | if (audioTrack != null) { 90 | System.out.println(counter.getAndIncrement() + ": " + formatter.format(Instant.now()) + " -> Rate: " + String.format("%.2f%%", ((float) (audioTrack.getPosition()) / audioTrack.getDuration()) * 100)); 91 | } 92 | }, 1, 10, TimeUnit.SECONDS); 93 | } 94 | 95 | private class TrackQueue implements ITrackQueue { 96 | 97 | private final Random random = new Random(); 98 | 99 | private final List tracks; 100 | 101 | public TrackQueue(List tracks) { 102 | System.out.println("Init track queue with " + tracks.size() + " tracks."); 103 | this.tracks = tracks; 104 | } 105 | 106 | @Override 107 | public boolean calculateNext() { 108 | return true; 109 | } 110 | 111 | @Override 112 | public IAudioTrack getNext() { 113 | return tracks.get(random.nextInt(tracks.size())); 114 | } 115 | 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/dependency/DependencyManager.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.dependency; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.io.OutputStream; 6 | import java.net.MalformedURLException; 7 | import java.net.URL; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | import java.nio.file.Paths; 11 | import java.nio.file.StandardOpenOption; 12 | import java.util.Collections; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | import java.util.stream.Stream; 16 | 17 | import org.apache.commons.io.FileUtils; 18 | import org.apache.logging.log4j.LogManager; 19 | import org.apache.logging.log4j.Logger; 20 | import org.apache.logging.log4j.Marker; 21 | import org.apache.logging.log4j.MarkerManager; 22 | 23 | import com.google.common.base.Predicates; 24 | 25 | import info.u_team.music_player.MusicPlayerReference; 26 | import info.u_team.music_player.dependency.classloader.DependencyClassLoader; 27 | import info.u_team.u_team_core.util.ServiceUtil; 28 | import net.minecraft.util.StringUtil; 29 | 30 | public class DependencyManager { 31 | 32 | private static final Logger LOGGER = LogManager.getLogger(); 33 | private static final Marker MARKER_LOAD = MarkerManager.getMarker("Load"); 34 | private static final Marker MARKER_ADD = MarkerManager.getMarker("Add"); 35 | 36 | private static final String FILE_ENDING = ".jar.packed"; 37 | 38 | private static final PathLocator PATH_LOCATOR = ServiceUtil.loadOne(PathLocator.class); 39 | 40 | public static final DependencyClassLoader MUSICPLAYER_CLASSLOADER = new DependencyClassLoader(); 41 | 42 | public static void load() { 43 | LOGGER.info(MARKER_LOAD, "Load dependencies"); 44 | 45 | final Path tmpPath = createExtractDirectory(); 46 | 47 | LOGGER.info(MARKER_LOAD, "Extraction directory for jar files is {} ", tmpPath.toAbsolutePath()); 48 | 49 | final String devPath = System.getProperty("musicplayer.dev"); 50 | final Set paths; 51 | if (devPath != null) { 52 | paths = Stream.of(devPath.split(";")) // 53 | .filter(Predicates.not(StringUtil::isNullOrEmpty)) // 54 | .map(Paths::get) // 55 | .map(DependencyManager::findJarFilesInDev) // 56 | .flatMap(Set::stream) // 57 | .collect(Collectors.toUnmodifiableSet()); 58 | } else { 59 | paths = findJarFilesInJar("dependencies"); 60 | } 61 | 62 | paths.stream() // 63 | .map(path -> extractFile(tmpPath, path)) // 64 | .map(DependencyManager::pathToUrl) // 65 | .forEach(DependencyManager::addToMusicPlayerDependencies); 66 | 67 | LOGGER.info(MARKER_LOAD, "Finished loading dependencies"); 68 | } 69 | 70 | private static Path createExtractDirectory() { 71 | try { 72 | final Path baseDirectory = Paths.get(System.getProperty("java.io.tmpdir", "/tmp"), MusicPlayerReference.MODID + "-extraction-tmp"); 73 | final Path specificDirectory = baseDirectory.resolve(String.valueOf(System.currentTimeMillis())); 74 | 75 | // Try to clean base directory before 76 | try { 77 | FileUtils.deleteDirectory(baseDirectory.toFile()); 78 | } catch (final Exception ex) { 79 | } 80 | 81 | Files.createDirectories(specificDirectory); 82 | return specificDirectory; 83 | } catch (final IOException unused) { 84 | try { 85 | return Files.createTempDirectory(MusicPlayerReference.MODID + "-extraction-tmp"); 86 | } catch (final IOException ex) { 87 | throw new RuntimeException("Cannot create extract directory for musicplayer files", ex); 88 | } 89 | } 90 | } 91 | 92 | private static Path extractFile(Path extractDirectory, Path path) { 93 | final Path extractPath = extractDirectory.resolve(path.getFileName().toString()); 94 | try (final InputStream inputStream = Files.newInputStream(path); // 95 | final OutputStream outputStream = Files.newOutputStream(extractPath, StandardOpenOption.CREATE);) { 96 | inputStream.transferTo(outputStream); 97 | LOGGER.debug(MARKER_LOAD, "Copied file from ({}) to ({})", path, extractPath); 98 | } catch (final IOException ex) { 99 | throw new RuntimeException("Cannot extract file " + path + " to " + extractPath, ex); 100 | } 101 | return extractPath; 102 | } 103 | 104 | private static URL pathToUrl(Path path) { 105 | try { 106 | return path.toUri().toURL(); 107 | } catch (final MalformedURLException ex) { 108 | throw new RuntimeException(ex); 109 | } 110 | } 111 | 112 | private static Set findJarFilesInDev(Path path) { 113 | try (final Stream stream = Files.walk(path)) { 114 | return filterPackedFiles(stream); 115 | } catch (final IOException ex) { 116 | LOGGER.error(MARKER_LOAD, "When searching for jar files in dev an exception occured.", ex); 117 | } 118 | return Collections.emptySet(); 119 | } 120 | 121 | private static Set findJarFilesInJar(String folder) { 122 | try (final Stream stream = Files.walk(PATH_LOCATOR.locate(MusicPlayerReference.MODID, folder))) { 123 | return filterPackedFiles(stream); 124 | } catch (final IOException | IllegalStateException ex) { 125 | LOGGER.error(MARKER_LOAD, "When searching for jar files in jar an exception occured.", ex); 126 | } 127 | return Collections.emptySet(); 128 | } 129 | 130 | private static Set filterPackedFiles(Stream stream) { 131 | return stream.filter(file -> file.toString().endsWith(FILE_ENDING)).collect(Collectors.toSet()); 132 | } 133 | 134 | private static void addToMusicPlayerDependencies(URL url) { 135 | MUSICPLAYER_CLASSLOADER.addURL(url); 136 | LOGGER.debug(MARKER_ADD, "Added new jar file ({}) to the musicplayer dependency classloader.", url); 137 | } 138 | 139 | public static interface PathLocator { 140 | 141 | Path locate(String modid, String folder) throws IOException, IllegalStateException; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /musicplayer-lavaplayer/src/main/java/info/u_team/music_player/lavaplayer/output/AudioOutput.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Thanks to VSETH-GECO for this amazing audio consumer class for lavaplayer (It is kind of changed) MIT License 3 | * Copyright (c) 2017 VSETH-GECO Permission is hereby granted, free of charge, to any person obtaining a copy of this 4 | * software and associated documentation files (the "Software"), to deal in the Software without restriction, including 5 | * without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 6 | * Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The 7 | * above copyright notice and this permission notice shall be included in all copies or substantial portions of the 8 | * Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 9 | * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 10 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 11 | * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 12 | * THE SOFTWARE. 13 | */ 14 | 15 | package info.u_team.music_player.lavaplayer.output; 16 | 17 | import java.util.Arrays; 18 | 19 | import javax.sound.sampled.AudioFormat; 20 | import javax.sound.sampled.AudioInputStream; 21 | import javax.sound.sampled.AudioSystem; 22 | import javax.sound.sampled.DataLine; 23 | import javax.sound.sampled.Line; 24 | import javax.sound.sampled.LineUnavailableException; 25 | import javax.sound.sampled.Mixer; 26 | import javax.sound.sampled.SourceDataLine; 27 | 28 | import com.sedmelluq.discord.lavaplayer.format.AudioDataFormat; 29 | import com.sedmelluq.discord.lavaplayer.format.AudioDataFormatTools; 30 | import com.sedmelluq.discord.lavaplayer.format.AudioPlayerInputStream; 31 | import com.sedmelluq.discord.lavaplayer.player.AudioPlayer; 32 | 33 | import info.u_team.music_player.lavaplayer.MusicPlayer; 34 | 35 | public class AudioOutput extends Thread { 36 | 37 | private final MusicPlayer musicPlayer; 38 | 39 | private final AudioFormat format; 40 | private final DataLine.Info speakerInfo; 41 | 42 | private Mixer mixer; 43 | private SourceDataLine souceLine; 44 | 45 | public AudioOutput(MusicPlayer musicPlayer) { 46 | super("Audio Player"); 47 | this.musicPlayer = musicPlayer; 48 | format = AudioDataFormatTools.toAudioFormat(musicPlayer.getAudioDataFormat()); 49 | speakerInfo = new DataLine.Info(SourceDataLine.class, format); 50 | setMixer(""); 51 | } 52 | 53 | @Override 54 | public void run() { 55 | try { 56 | final AudioPlayer player = musicPlayer.getAudioPlayer(); 57 | final AudioDataFormat dataformat = musicPlayer.getAudioDataFormat(); 58 | 59 | final AudioInputStream stream = AudioPlayerInputStream.createStream(player, dataformat, dataformat.frameDuration(), false); 60 | 61 | final byte[] buffer = new byte[dataformat.chunkSampleCount * dataformat.channelCount * 2]; 62 | final long frameDuration = dataformat.frameDuration(); 63 | int chunkSize; 64 | while (true) { 65 | if (souceLine == null || !souceLine.isOpen()) { 66 | closeLine(); 67 | if (!createLine()) { 68 | sleep(500); 69 | continue; 70 | } 71 | } 72 | if (!player.isPaused()) { 73 | if ((chunkSize = stream.read(buffer)) >= 0) { 74 | souceLine.write(buffer, 0, chunkSize); 75 | if (musicPlayer.getOutputConsumer() != null) { 76 | musicPlayer.getOutputConsumer().accept(Arrays.copyOf(buffer, buffer.length), chunkSize); 77 | } 78 | } else { 79 | throw new IllegalStateException("Audiostream ended. This should not happen."); 80 | } 81 | } else { 82 | souceLine.drain(); 83 | sleep(frameDuration); 84 | } 85 | } 86 | } catch (final Exception ex) { 87 | ex.printStackTrace(); 88 | } 89 | } 90 | 91 | public void setMixer(String name) { 92 | if (mixer != null && mixer.getMixerInfo().getName().equals(name)) { 93 | return; 94 | } 95 | final Mixer oldMixer = mixer; 96 | mixer = findMixer(name, speakerInfo); 97 | closeLine(); 98 | if (oldMixer != null) { 99 | if (!hasLinesOpen(oldMixer)) { 100 | oldMixer.close(); 101 | } 102 | } 103 | } 104 | 105 | public String getMixer() { 106 | if (mixer == null) { 107 | return null; 108 | } 109 | return mixer.getMixerInfo().getName(); 110 | } 111 | 112 | public DataLine.Info getSpeakerInfo() { 113 | return speakerInfo; 114 | } 115 | 116 | private boolean createLine() { 117 | if (mixer != null) { 118 | try { 119 | final SourceDataLine line = (SourceDataLine) mixer.getLine(speakerInfo); 120 | final AudioDataFormat dataFormat = musicPlayer.getAudioDataFormat(); 121 | line.open(format, dataFormat.chunkSampleCount * dataFormat.channelCount * 2 * 5); 122 | line.start(); 123 | souceLine = line; 124 | return true; 125 | } catch (final LineUnavailableException ex) { 126 | } 127 | } 128 | return false; 129 | } 130 | 131 | private void closeLine() { 132 | if (souceLine != null) { 133 | souceLine.flush(); 134 | souceLine.stop(); 135 | souceLine.close(); 136 | } 137 | } 138 | 139 | private Mixer findMixer(String name, Line.Info lineInfo) { 140 | Mixer defaultMixer = null; 141 | for (final Mixer.Info mixerInfo : AudioSystem.getMixerInfo()) { 142 | final Mixer mixer = AudioSystem.getMixer(mixerInfo); 143 | if (mixer.isLineSupported(lineInfo)) { 144 | if (mixerInfo.getName().equals(name)) { 145 | return mixer; 146 | } 147 | if (defaultMixer == null) { 148 | defaultMixer = mixer; 149 | } 150 | } 151 | } 152 | return defaultMixer; 153 | } 154 | 155 | public static boolean hasLinesOpen(Mixer mixer) { 156 | return mixer.getSourceLines().length != 0 || mixer.getTargetLines().length != 0; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /common/src/common/java/info/u_team/music_player/gui/GuiMusicPlayerListEntry.java: -------------------------------------------------------------------------------- 1 | package info.u_team.music_player.gui; 2 | 3 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_PLAYLISTS_ENTRIES; 4 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_PLAYLISTS_ENTRY; 5 | import static info.u_team.music_player.init.MusicPlayerLocalization.GUI_PLAYLISTS_NO_NAME; 6 | import static info.u_team.music_player.init.MusicPlayerLocalization.getTranslation; 7 | 8 | import org.apache.commons.lang3.tuple.Pair; 9 | 10 | import info.u_team.music_player.gui.playlist.GuiMusicPlaylist; 11 | import info.u_team.music_player.init.MusicPlayerResources; 12 | import info.u_team.music_player.lavaplayer.api.audio.IAudioTrack; 13 | import info.u_team.music_player.lavaplayer.api.queue.ITrackManager; 14 | import info.u_team.music_player.musicplayer.MusicPlayerManager; 15 | import info.u_team.music_player.musicplayer.playlist.LoadedTracks; 16 | import info.u_team.music_player.musicplayer.playlist.Playlist; 17 | import info.u_team.music_player.musicplayer.playlist.Playlists; 18 | import info.u_team.music_player.musicplayer.playlist.Skip; 19 | import info.u_team.u_team_core.gui.elements.ImageButton; 20 | import info.u_team.u_team_core.gui.elements.ImageToggleButton; 21 | import net.minecraft.client.gui.GuiGraphics; 22 | import net.minecraft.network.chat.CommonComponents; 23 | import net.minecraft.network.chat.Component; 24 | 25 | class GuiMusicPlayerListEntry extends BetterScrollableListEntry { 26 | 27 | private final Playlists playlists; 28 | private final Playlist playlist; 29 | 30 | private final ImageToggleButton playPlaylistButton; 31 | private final ImageButton openPlaylistButton; 32 | private final ImageButton deletePlaylistButton; 33 | 34 | public GuiMusicPlayerListEntry(GuiMusicPlayerList gui, Playlists playlists, Playlist playlist) { 35 | this.playlists = playlists; 36 | this.playlist = playlist; 37 | 38 | playPlaylistButton = addChildren(new ImageToggleButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_PLAY, MusicPlayerResources.TEXTURE_STOP, playlist.equals(playlists.getPlaying()))); 39 | playPlaylistButton.active = !playlists.isPlayingLock(); 40 | 41 | playPlaylistButton.setPressable(() -> { 42 | final boolean play = playPlaylistButton.isToggled(); 43 | if (playlists.isPlayingLock()) { 44 | return; 45 | } 46 | playlists.setPlaying(null); 47 | gui.children().stream().filter(entry -> entry != this).forEach(entry -> entry.playPlaylistButton.setToggled(false)); // Reset all playlist buttons except this one 48 | 49 | final Runnable runnable = () -> { 50 | final ITrackManager manager = MusicPlayerManager.getPlayer().getTrackManager(); 51 | 52 | // Start playlist 53 | if (play) { 54 | if (!playlist.isEmpty()) { 55 | playlists.setPlaying(playlist); 56 | final Pair pair = playlist.getFirstTrack(); 57 | playlist.setPlayable(pair.getLeft(), pair.getRight()); 58 | if (pair.getLeft().hasError() || pair.getRight() == null) { 59 | playlist.skip(Skip.FORWARD); 60 | } 61 | manager.setTrackQueue(playlist); 62 | manager.start(); 63 | } else { 64 | playlists.setPlaying(null); 65 | playlist.setStopable(); 66 | manager.stop(); 67 | playPlaylistButton.setToggled(false); 68 | } 69 | } else { 70 | playlists.setPlaying(null); 71 | playlist.setStopable(); 72 | manager.stop(); 73 | } 74 | 75 | playlists.removePlayingLock(); 76 | 77 | if (minecraft.screen instanceof final GuiMusicPlayer musicplayergui) { 78 | final GuiMusicPlayerList newGui = musicplayergui.getPlaylistsList(); 79 | newGui.children().forEach(entry -> entry.playPlaylistButton.active = true); 80 | } else if (minecraft.screen instanceof final GuiMusicPlaylist musicplaylistgui) { 81 | musicplaylistgui.getTrackList().updateAllEntries(); 82 | } 83 | }; 84 | 85 | gui.children().forEach(entry -> entry.playPlaylistButton.active = false); 86 | playlists.setPlayingLock(); 87 | 88 | if (!playlist.isLoaded()) { 89 | playlist.load(runnable); 90 | } else { 91 | runnable.run(); 92 | } 93 | }); 94 | 95 | openPlaylistButton = addChildren(new ImageButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_OPEN)); 96 | openPlaylistButton.setPressable(() -> minecraft.setScreen(new GuiMusicPlaylist(playlist))); 97 | 98 | deletePlaylistButton = addChildren(new ImageButton(0, 0, 20, 20, MusicPlayerResources.TEXTURE_CLEAR)); 99 | deletePlaylistButton.setPressable(() -> gui.removePlaylist(this)); 100 | } 101 | 102 | @Override 103 | public void render(GuiGraphics guiGraphics, int slotIndex, int entryY, int entryX, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float partialTicks) { 104 | String name = playlist.getName(); 105 | if (name.isEmpty()) { 106 | name = "\u00A7o" + getTranslation(GUI_PLAYLISTS_NO_NAME); 107 | } 108 | guiGraphics.drawString(minecraft.font, name, entryX + 5, entryY + 5, playlist.equals(playlists.getPlaying()) ? 0x0083FF : 0xFFF00F, false); 109 | guiGraphics.drawString(minecraft.font, playlist.getEntrySize() + " " + getTranslation(playlist.getEntrySize() > 1 ? GUI_PLAYLISTS_ENTRIES : GUI_PLAYLISTS_ENTRY), entryX + 5, entryY + 30, 0xFFFFFF, false); 110 | 111 | playPlaylistButton.setX(entryWidth - 65); 112 | playPlaylistButton.setY(entryY + 12); 113 | playPlaylistButton.render(guiGraphics, mouseX, mouseY, partialTicks); 114 | 115 | openPlaylistButton.setX(entryWidth - 40); 116 | openPlaylistButton.setY(entryY + 12); 117 | openPlaylistButton.render(guiGraphics, mouseX, mouseY, partialTicks); 118 | 119 | deletePlaylistButton.setX(entryWidth - 15); 120 | deletePlaylistButton.setY(entryY + 12); 121 | deletePlaylistButton.render(guiGraphics, mouseX, mouseY, partialTicks); 122 | } 123 | 124 | public Playlist getPlaylist() { 125 | return playlist; 126 | } 127 | 128 | @Override 129 | public Component getNarration() { 130 | return CommonComponents.EMPTY; 131 | } 132 | } -------------------------------------------------------------------------------- /forge/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "net.minecraftforge.gradle" 3 | id "org.parchmentmc.librarian.forgegradle" 4 | id "org.spongepowered.mixin" 5 | id "info.u_team.gradle_files" 6 | id "me.modmuss50.mod-publish-plugin" 7 | id "maven-publish" 8 | id "com.gradleup.shadow" version "8.3.6" 9 | } 10 | 11 | gradlefiles.loaderSuffix = "forge" 12 | 13 | group = rootProject.group 14 | base.archivesName = gradlefiles.archivesName() 15 | version = gradlefiles.version() 16 | 17 | sourceSets { 18 | main { 19 | java { 20 | srcDirs += gradlefiles.project("common").sourceSets.common.java.srcDirs 21 | } 22 | resources { 23 | srcDirs += gradlefiles.project("common").sourceSets.common.resources.srcDirs 24 | } 25 | } 26 | } 27 | 28 | java { 29 | toolchain { 30 | languageVersion = JavaLanguageVersion.of(21) 31 | } 32 | withSourcesJar() 33 | withJavadocJar() 34 | } 35 | 36 | configurations { 37 | shade 38 | library 39 | library.extendsFrom(shade) 40 | minecraftLibrary.extendsFrom(library) 41 | } 42 | 43 | minecraft { 44 | mappings channel: config.forge.mapping_channel, version: config.forge.mapping 45 | 46 | reobf = false 47 | 48 | accessTransformer = file("src/main/resources/META-INF/accesstransformer.cfg") 49 | 50 | runs { 51 | client { 52 | workingDirectory file("run/client") 53 | property "musicplayer.dev", getRootProject().lavaplayerLibraries() 54 | 55 | mods { 56 | "${config.mod.modid}" { 57 | source sourceSets.main 58 | } 59 | } 60 | } 61 | 62 | server { 63 | workingDirectory file("run/server") 64 | 65 | mods { 66 | "${config.mod.modid}" { 67 | source sourceSets.main 68 | } 69 | } 70 | } 71 | } 72 | } 73 | 74 | mixin { 75 | config "musicplayer.mixins.json" 76 | 77 | debug.verbose = true 78 | debug.export = true 79 | } 80 | 81 | evaluationDependsOn(":musicplayer-lavaplayer") 82 | 83 | tasks.matching { task -> task.name == "prepareRuns" }.configureEach { 84 | dependsOn project(":musicplayer-lavaplayer").tasks.named("assemble") 85 | } 86 | 87 | tasks.named("shadowJar").configure { 88 | dependsOn tasks.named("jar") 89 | dependsOn project(":musicplayer-lavaplayer-api").tasks.named("assemble") 90 | dependsOn project(":musicplayer-lavaplayer").tasks.named("assemble") 91 | 92 | archiveClassifier = tasks.named("jar").flatMap { jar -> jar.archiveClassifier } 93 | destinationDirectory = tasks.named("jar").flatMap { jar -> jar.destinationDirectory } 94 | 95 | configurations = [project.configurations.shade] 96 | 97 | from sourceSets.main.output 98 | from project(":musicplayer-lavaplayer").file("src/main/resources/LICENSE-DEPENDENCIES") 99 | 100 | doFirst { 101 | from project(":musicplayer-lavaplayer-api").sourceSets.main.output 102 | } 103 | 104 | into ("dependencies") { 105 | final def buildDir = project(":musicplayer-lavaplayer").layout.buildDirectory 106 | from buildDir.dir("libs").get().file("musicplayer-lavaplayer.jar.packed") 107 | from buildDir.dir("dependencies") 108 | } 109 | 110 | relocate "net.harawata.appdirs", "info.u_team.music_player.shade.net.harawata.appdirs" 111 | 112 | exclude "META-INF/maven/**" 113 | } 114 | 115 | components.named("java").configure { 116 | withVariantsFromConfiguration(configurations.named("shadowRuntimeElements").get()) { 117 | skip() 118 | } 119 | } 120 | 121 | tasks.withType(Jar).configureEach { task -> 122 | gradlefiles.defaultJar(task) 123 | 124 | manifest { 125 | attributes("MixinConfigs": "musicplayer.mixins.json") 126 | } 127 | } 128 | tasks.withType(Javadoc).configureEach { task -> 129 | task.options.addStringOption("Xdoclint:none", "-quiet") 130 | } 131 | 132 | signjar.sign(tasks.named("shadowJar")) 133 | 134 | processResources { 135 | doLast { 136 | fileTree(dir: outputs.files.asPath, include: "**/*.json").each { File file -> 137 | file.text = groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parse(file)) 138 | } 139 | } 140 | } 141 | 142 | repositories { 143 | maven { 144 | url = "https://maven.minecraftforge.net" 145 | } 146 | maven { 147 | url = "https://repo.u-team.info" 148 | } 149 | mavenCentral() 150 | } 151 | 152 | dependencies { 153 | minecraft gradlefiles.forgeDependency() 154 | 155 | // Fix wrong jopt simple version 156 | implementation("net.sf.jopt-simple:jopt-simple:5.0.4") { 157 | version { 158 | strictly "5.0.4" 159 | } 160 | } 161 | 162 | implementation "info.u-team:u_team_core-forge-1.21.1:5.6.2.384" 163 | 164 | library project(":musicplayer-lavaplayer-api") 165 | shade ("net.harawata:appdirs:1.4.0") { 166 | transitive=false 167 | } 168 | } 169 | 170 | publishMods { 171 | file = tasks.named("jar").flatMap { jar -> jar.archiveFile } 172 | displayName = "${config.publish.display}-Forge-${config.minecraft.version}-${project.version}" 173 | changelog = "[Changelog for version ${project.version}](${gradlefiles.changelogUrl()})" 174 | type = me.modmuss50.mpp.ReleaseType.of(config.publish.type) 175 | modLoaders.add("forge") 176 | 177 | curseforge { 178 | accessToken = defaultPropertyValue("curseforge.token") 179 | 180 | projectId = config.curse.id 181 | projectSlug = config.curse.slug 182 | minecraftVersions.add(config.minecraft.version) 183 | javaVersions.add(JavaVersion.VERSION_21) 184 | clientRequired = true 185 | 186 | requires("u-team-core") 187 | optional("voice-chat") 188 | } 189 | 190 | modrinth { 191 | accessToken = defaultPropertyValue("modrinth.token") 192 | 193 | projectId = config.modrinth.id 194 | minecraftVersions.add(config.minecraft.version) 195 | 196 | requires("u-team-core") 197 | } 198 | 199 | discord { 200 | webhookUrl = defaultPropertyValue("discord.update_webhook") 201 | 202 | username = "Mod Update" 203 | avatarUrl = "https://raw.githubusercontent.com/MC-U-Team/${config.github.name}/${config.github.branch}/logo.png" 204 | 205 | content = changelog.map { log -> "# ${config.minecraft.version}: ${config.publish.display} (Forge)\n" + log} 206 | } 207 | } 208 | 209 | publishing { 210 | repositories { 211 | maven { 212 | url = "https://repo.u-team.info" 213 | credentials { 214 | username = "maven" 215 | password = defaultPropertyValue("maven.password") 216 | } 217 | } 218 | } 219 | publications { 220 | mavenJava(MavenPublication) { 221 | artifactId = project.base.archivesName.get() 222 | 223 | from gradlefiles.filteredJavaComponent { 224 | filterDependency { holder -> 225 | "appdirs" == holder.dependency.name 226 | } 227 | filterDependency { holder -> 228 | "musicplayer-lavaplayer-api" == holder.dependency.name 229 | } 230 | filterDependency { holder -> 231 | "jopt-simple" == holder.dependency.name 232 | } 233 | } 234 | 235 | pom { 236 | pom.name = project.base.archivesName.get() 237 | rootProject.commonPom(it) 238 | } 239 | } 240 | } 241 | } -------------------------------------------------------------------------------- /fabric/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "fabric-loom" 3 | id "info.u_team.gradle_files" 4 | id "me.modmuss50.mod-publish-plugin" 5 | id "maven-publish" 6 | id "com.gradleup.shadow" version "8.3.6" 7 | } 8 | 9 | gradlefiles.loaderSuffix = "fabric" 10 | 11 | group = rootProject.group 12 | base.archivesName = gradlefiles.archivesName() 13 | version = gradlefiles.version() 14 | 15 | sourceSets { 16 | main { 17 | java { 18 | srcDirs += gradlefiles.project("common").sourceSets.common.java.srcDirs 19 | } 20 | resources { 21 | srcDirs += gradlefiles.project("common").sourceSets.common.resources.srcDirs 22 | } 23 | } 24 | } 25 | 26 | java { 27 | toolchain { 28 | languageVersion = JavaLanguageVersion.of(21) 29 | } 30 | withSourcesJar() 31 | withJavadocJar() 32 | } 33 | 34 | configurations { 35 | shade 36 | library 37 | library.extendsFrom(shade) 38 | implementation.extendsFrom(library) 39 | } 40 | 41 | loom { 42 | accessWidenerPath = file("src/main/resources/musicplayer.accesswidener") 43 | 44 | runs { 45 | client { 46 | runDir "run/client" 47 | property "musicplayer.dev", getRootProject().lavaplayerLibraries() 48 | ideConfigGenerated true 49 | } 50 | 51 | server { 52 | runDir "run/server" 53 | ideConfigGenerated true 54 | } 55 | } 56 | 57 | mixin { 58 | defaultRefmapName = "musicplayer.mixins.refmap.json" 59 | } 60 | } 61 | 62 | evaluationDependsOn(":musicplayer-lavaplayer") 63 | 64 | afterEvaluate { 65 | net.fabricmc.loom.task.LoomTasks.getIDELaunchConfigureTaskName(project).get().configure { 66 | dependsOn project(":musicplayer-lavaplayer").tasks.named("assemble") 67 | } 68 | } 69 | 70 | tasks.named("shadowJar").configure { 71 | dependsOn tasks.named("jar") 72 | dependsOn project(":musicplayer-lavaplayer-api").tasks.named("assemble") 73 | dependsOn project(":musicplayer-lavaplayer").tasks.named("assemble") 74 | 75 | archiveClassifier = tasks.named("jar").flatMap { jar -> jar.archiveClassifier } 76 | destinationDirectory = tasks.named("jar").flatMap { jar -> jar.destinationDirectory } 77 | 78 | configurations = [project.configurations.shade] 79 | 80 | from sourceSets.main.output 81 | from project(":musicplayer-lavaplayer").file("src/main/resources/LICENSE-DEPENDENCIES") 82 | 83 | doFirst { 84 | from project(":musicplayer-lavaplayer-api").sourceSets.main.output 85 | } 86 | 87 | into ("dependencies") { 88 | final def buildDir = project(":musicplayer-lavaplayer").layout.buildDirectory 89 | from buildDir.dir("libs").get().file("musicplayer-lavaplayer.jar.packed") 90 | from buildDir.dir("dependencies") 91 | } 92 | 93 | relocate "net.harawata.appdirs", "info.u_team.music_player.shade.net.harawata.appdirs" 94 | 95 | exclude "META-INF/maven/**" 96 | } 97 | 98 | components.named("java").configure { 99 | withVariantsFromConfiguration(configurations.named("shadowRuntimeElements").get()) { 100 | skip() 101 | } 102 | } 103 | 104 | tasks.named("remapJar").configure { 105 | dependsOn tasks.named("shadowJar") 106 | } 107 | 108 | tasks.withType(Jar).configureEach { task -> 109 | gradlefiles.defaultJar(task) 110 | } 111 | 112 | tasks.withType(Javadoc).configureEach { task -> 113 | task.options.addStringOption("Xdoclint:none", "-quiet") 114 | } 115 | 116 | signjar.sign(tasks.named("remapJar")) 117 | 118 | processResources { 119 | doLast { 120 | fileTree(dir: outputs.files.asPath, include: "**/*.json").each { File file -> 121 | file.text = groovy.json.JsonOutput.toJson(new groovy.json.JsonSlurper().parse(file)) 122 | } 123 | } 124 | } 125 | 126 | processResources { 127 | inputs.property "version", project.version 128 | 129 | filesMatching("fabric.mod.json") { 130 | expand "version": project.version 131 | } 132 | } 133 | 134 | repositories { 135 | maven { 136 | url = "https://maven.fabricmc.net" 137 | } 138 | maven { 139 | url = "https://maven.parchmentmc.org" 140 | } 141 | maven { 142 | url = "https://repo.u-team.info" 143 | } 144 | maven { 145 | url = "https://maven.terraformersmc.com" 146 | } 147 | mavenCentral() 148 | } 149 | 150 | dependencies { 151 | minecraft gradlefiles.fabricMinecraftDependency() 152 | mappings loom.layered() { 153 | officialMojangMappings() 154 | parchment(config.fabric.mapping_layer) 155 | } 156 | 157 | modImplementation gradlefiles.fabricLoaderDependency() 158 | modImplementation gradlefiles.fabricApiDependency() 159 | 160 | modImplementation "info.u-team:u_team_core-fabric-1.21.1:5.6.2.384" 161 | 162 | modRuntimeOnly "com.terraformersmc:modmenu:${config.modmenu.fabric.version}" 163 | 164 | library project(":musicplayer-lavaplayer-api") 165 | shade ("net.harawata:appdirs:1.4.0") { 166 | transitive=false 167 | } 168 | } 169 | 170 | publishMods { 171 | file = tasks.named("remapJar").flatMap { jar -> jar.archiveFile } 172 | displayName = "${config.publish.display}-Fabric-${config.minecraft.version}-${project.version}" 173 | changelog = "[Changelog for version ${project.version}](${gradlefiles.changelogUrl()})" 174 | type = me.modmuss50.mpp.ReleaseType.of(config.publish.type) 175 | modLoaders.add("fabric") 176 | 177 | curseforge { 178 | accessToken = defaultPropertyValue("curseforge.token") 179 | 180 | projectId = config.curse.id 181 | projectSlug = config.curse.slug 182 | minecraftVersions.add(config.minecraft.version) 183 | javaVersions.add(JavaVersion.VERSION_21) 184 | clientRequired = true 185 | 186 | requires("fabric-api") 187 | requires("u-team-core") 188 | } 189 | 190 | modrinth { 191 | accessToken = defaultPropertyValue("modrinth.token") 192 | 193 | projectId = config.modrinth.id 194 | minecraftVersions.add(config.minecraft.version) 195 | 196 | requires("fabric-api") 197 | requires("u-team-core") 198 | } 199 | 200 | discord { 201 | webhookUrl = defaultPropertyValue("discord.update_webhook") 202 | 203 | username = "Mod Update" 204 | avatarUrl = "https://raw.githubusercontent.com/MC-U-Team/${config.github.name}/${config.github.branch}/logo.png" 205 | 206 | content = changelog.map { log -> "# ${config.minecraft.version}: ${config.publish.display} (Fabric)\n" + log} 207 | } 208 | } 209 | 210 | publishing { 211 | repositories { 212 | maven { 213 | url = "https://repo.u-team.info" 214 | credentials { 215 | username = "maven" 216 | password = defaultPropertyValue("maven.password") 217 | } 218 | } 219 | } 220 | publications { 221 | mavenJava(MavenPublication) { 222 | artifactId = project.base.archivesName.get() 223 | 224 | from gradlefiles.filteredJavaComponent { 225 | filterDependency { holder -> 226 | "appdirs" == holder.dependency.name 227 | } 228 | filterDependency { holder -> 229 | "musicplayer-lavaplayer-api" == holder.dependency.name 230 | } 231 | filterDependency { holder -> 232 | "modmenu" == holder.dependency.name 233 | } 234 | } 235 | 236 | pom { 237 | pom.name = project.base.archivesName.get() 238 | rootProject.commonPom(it) 239 | } 240 | } 241 | } 242 | } 243 | --------------------------------------------------------------------------------