Skip to content

Commit

Permalink
Progression in spotify support
Browse files Browse the repository at this point in the history
  • Loading branch information
tttsaurus committed Jan 7, 2025
1 parent 80094cf commit 2b3eca1
Show file tree
Hide file tree
Showing 18 changed files with 241 additions and 37 deletions.
27 changes: 27 additions & 0 deletions src/main/java/com/tttsaurus/ingameinfo/IgiConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.tttsaurus.ingameinfo;

import net.minecraftforge.common.config.Configuration;

public class IgiConfig
{
public static String SPOTIFY_CLIENT_ID;
public static String SPOTIFY_CLIENT_SECRET;

public static Configuration CONFIG;

public static void loadConfig()
{
try
{
CONFIG.load();

SPOTIFY_CLIENT_ID = CONFIG.getString("Spotify Client Id", "spotify", "", "Input client id of your spotify app \nDeclaration: this mod doesn't record or share your client id \nand it's not recommended for you to share your client id \nGuide: you have to create a spotify app to get client id & secrete \nhttps://developer.spotify.com/documentation/web-api/concepts/apps \nRedirect URI should be set to http://localhost:8888 for this mod to listen");
SPOTIFY_CLIENT_SECRET = CONFIG.getString("Spotify Client Secret", "spotify", "", "Input client secret of your spotify app \nDeclaration: this mod doesn't record or share your client secret \nand it's not recommended for you to share your client secret");
}
catch (Exception ignored) { }
finally
{
if (CONFIG.hasChanged()) CONFIG.save();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public static TrackPlaying getCurrentlyPlaying(String accessToken) throws Except
String album = RawJsonUtils.extractValue(item, "album");
String images = RawJsonUtils.extractValue(album, "images");
List<String> imageList = RawJsonUtils.splitArray(images);
track.albumImage64by64 = RawJsonUtils.extractValue(imageList.get(0), "url");
track.albumImage64by64 = RawJsonUtils.extractValue(imageList.get(2), "url");
track.albumImage300by300 = RawJsonUtils.extractValue(imageList.get(1), "url");
track.albumImage640by640 = RawJsonUtils.extractValue(imageList.get(2), "url");
track.albumImage640by640 = RawJsonUtils.extractValue(imageList.get(0), "url");

String artists = RawJsonUtils.extractValue(item, "artists");
List<String> artistList = RawJsonUtils.splitArray(artists);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import javax.net.ssl.HttpsURLConnection;

@SuppressWarnings("all")
Expand Down Expand Up @@ -45,6 +45,19 @@ public void handle(HttpExchange exchange) throws IOException
{
SpotifyUserInfo.token = getToken(authorizationCode);

// write it to local cache
File directory = new File("config/ingameinfo/cache");
if (!directory.exists()) directory.mkdirs();
try
{
RandomAccessFile file = new RandomAccessFile("config/ingameinfo/cache/spotify_refresh_token.txt", "rw");
file.setLength(0);
file.seek(0);
file.write(SpotifyUserInfo.token.refreshToken.getBytes(StandardCharsets.UTF_8));
file.close();
}
catch (Exception ignored) { }

String response = "<h1>[In-Game Info Reborn]</h1><br><h2>Authorization Successful</h2><p>You can close this window</p>";
byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
Expand Down Expand Up @@ -80,8 +93,8 @@ public void handle(HttpExchange exchange) throws IOException
}
}

public static final String CLIENT_ID = "";
public static final String CLIENT_SECRET = "";
public static String CLIENT_ID = "";
public static String CLIENT_SECRET = "";

// make sure this matches the redirect uri registered in your Spotify app
private static final String REDIRECT_URI = "http://localhost:8888";
Expand Down Expand Up @@ -197,6 +210,6 @@ public static void refreshAccessToken(Token token) throws IOException

token.accessToken = accessToken;
token.expiresIn = Integer.parseInt(expiresIn);
token.start = LocalDate.now();
token.start = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package com.tttsaurus.ingameinfo.common.api.appcommunication.spotify;

import java.time.LocalDate;
import java.time.LocalDateTime;

public class Token
{
public String accessToken;
public String refreshToken;

public int expiresIn;
public LocalDate start;
public LocalDateTime start;

public Token(String accessToken, String refreshToken, int expiresIn)
{
this.accessToken = accessToken;
this.refreshToken = refreshToken;
this.expiresIn = expiresIn;
this.start = LocalDate.now();
this.start = LocalDateTime.now();
}

public Token()
{
accessToken = "";
refreshToken = "";
expiresIn = 0;
start = LocalDate.now();
start = LocalDateTime.now();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class IgiGuiContainer
protected int backgroundColor = -1072689136;

private boolean initFlag = false;
private boolean active = true;

//<editor-fold desc="getters">
public int getExitKeyForFocusedGui() { return exitKeyForFocusedGui; }
Expand All @@ -49,6 +50,7 @@ public void onInit()
mainGroup.calcRenderPos(mainGroup.rect);
mainGroup.finishReCalc();

viewModel.activeSetter = (flag) -> { active = flag; };
viewModel.start();
}
public void onScaledResolutionResize()
Expand All @@ -59,10 +61,15 @@ public void onScaledResolutionResize()
}
public void onFixedUpdate(double deltaTime)
{
if (!active) return;

viewModel.onFixedUpdate(deltaTime);
mainGroup.onFixedUpdate(deltaTime);
}
public void onRenderUpdate(boolean focused)
{
if (!active) return;

if (isFocused && hasFocusBackground)
{
ScaledResolution resolution = new ScaledResolution(Minecraft.getMinecraft());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,11 @@ private GuiLayout init()
}
}

file.close();

GuiLayoutDeserializer deserializer = new GuiLayoutDeserializer();
GuiLayout guiLayout = deserializer.deserialize(builder.toString(), "ixml");

file.close();

return guiLayout;
}
catch (Exception ignored) { return InternalMethods.instance.GuiLayout$constructor.invoke(); }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.tttsaurus.ingameinfo.common.api.mvvm.viewmodel;

import com.tttsaurus.ingameinfo.common.api.gui.GuiLayout;
import com.tttsaurus.ingameinfo.common.api.internal.IAction_1Param;
import com.tttsaurus.ingameinfo.common.api.mvvm.binding.IReactiveObjectGetter;
import com.tttsaurus.ingameinfo.common.api.mvvm.binding.Reactive;
import com.tttsaurus.ingameinfo.common.api.mvvm.binding.VvmBinding;
Expand All @@ -13,6 +14,8 @@
@SuppressWarnings("all")
public abstract class ViewModel<T extends View>
{
public IAction_1Param<Boolean> activeSetter;

private VvmBinding<T> binding = new VvmBinding<>();

// init entry point
Expand All @@ -28,4 +31,5 @@ private GuiLayout init(String mvvmRegistryName)
}

public abstract void start();
public abstract void onFixedUpdate(double deltaTime);
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

public final class RenderUtils
{
Expand Down Expand Up @@ -248,8 +250,12 @@ public static void renderRectOutline(float x, float y, float width, float height
GlStateManager.popMatrix();
}

private static final IntBuffer intBuffer = ByteBuffer.allocateDirect(16 << 2).order(ByteOrder.nativeOrder()).asIntBuffer();
public static void renderTexture2D(float x, float y, float width, float height, int textureWidth, int textureHeight)
{
GL11.glGetInteger(GL11.GL_TEXTURE_BINDING_2D, intBuffer);
int textureID = intBuffer.get(0);

GlStateManager.enableTexture2D();
GlStateManager.disableLighting();
GlStateManager.enableBlend();
Expand All @@ -263,6 +269,8 @@ public static void renderTexture2D(float x, float y, float width, float height,
GlStateManager.scale(width/(float)((int)(width)), height/(float)((int)(height)), 0);
Gui.drawScaledCustomSizeModalRect(0, 0, 0, 0, textureWidth, textureHeight, (int)width, (int)height, textureWidth, textureHeight);
GlStateManager.popMatrix();

GlStateManager.bindTexture(textureID);
}

public static Texture2D getInGameScreenShot(int x, int y, int width, int height)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package com.tttsaurus.ingameinfo.common.impl.appcommunication.spotify;

import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyAccessUtils;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyOAuthUtils;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.TrackPlaying;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyUserInfo;
import com.tttsaurus.ingameinfo.common.impl.render.renderer.UrlImageRenderer;
import com.tttsaurus.ingameinfo.common.impl.igievent.EventCenter;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.util.text.Style;
Expand Down Expand Up @@ -42,10 +40,10 @@ public static void onChatReceived(ClientChatReceivedEvent event)
else if (message.startsWith("#spotify-oauth-code"))
{
event.setCanceled(true);
player.sendMessage(new TextComponentString(TextFormatting.DARK_PURPLE + message));
String[] args = message.split(" ");
if (args.length == 2)
{
player.sendMessage(new TextComponentString(TextFormatting.DARK_PURPLE + message));
String authorizationCode = args[1];
try
{
Expand All @@ -62,38 +60,29 @@ else if (message.startsWith("#spotify-oauth-code"))
}
}
}
else if (message.startsWith("#spotify-ui-display"))
else if (message.startsWith("#spotify-gui"))
{
event.setCanceled(true);
player.sendMessage(new TextComponentString(TextFormatting.DARK_PURPLE + message));
String[] args = message.split(" ");
if (args.length == 2)
{
String param = args[1];
if (param.equals("true") || param.equals("false"))
{
player.sendMessage(new TextComponentString(TextFormatting.DARK_PURPLE + message));
boolean flag = param.equals("true");
if (flag)
{
if (SpotifyUserInfo.token.accessToken.isEmpty())
{
player.sendMessage(new TextComponentString(TextFormatting.AQUA + "[SpotifyBot]" + TextFormatting.RESET + " The access token is empty."));
player.sendMessage(new TextComponentString(TextFormatting.AQUA + "[SpotifyBot]" + TextFormatting.RESET + " Please run the command #spotify-oauth first."));
return;
}
try
{
TrackPlaying trackPlaying = SpotifyAccessUtils.getCurrentlyPlaying(SpotifyUserInfo.token.accessToken);
player.sendMessage(new TextComponentString(TextFormatting.AQUA + "[SpotifyBot]" + TextFormatting.RESET + " " + trackPlaying.trackName));
trackPlaying.artists.forEach(str -> player.sendMessage(new TextComponentString(TextFormatting.AQUA + "[SpotifyBot]" + TextFormatting.RESET + " " + str)));
UrlImageRenderer.SHARED.updateURL(trackPlaying.albumImage640by640);
}
catch (Exception e)
{
player.sendMessage(new TextComponentString(TextFormatting.AQUA + "[SpotifyBot]" + TextFormatting.RESET + " Exception: " + e.getMessage()));
return;
}
// display
EventCenter.spotifyOverlayEvent.trigger(true);
}
else
EventCenter.spotifyOverlayEvent.trigger(false);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,108 @@
package com.tttsaurus.ingameinfo.common.impl.appcommunication.spotify;

import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyAccessUtils;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyOAuthUtils;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.SpotifyUserInfo;
import com.tttsaurus.ingameinfo.common.api.appcommunication.spotify.TrackPlaying;
import com.tttsaurus.ingameinfo.common.api.mvvm.binding.Reactive;
import com.tttsaurus.ingameinfo.common.api.mvvm.binding.ReactiveObject;
import com.tttsaurus.ingameinfo.common.api.mvvm.viewmodel.ViewModel;
import com.tttsaurus.ingameinfo.common.impl.igievent.EventCenter;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;

public class SpotifyViewModel extends ViewModel<SpotifyView>
{
@Reactive(targetUid = "albumImage", property = "url", initiativeSync = true)
public ReactiveObject<String> albumImageUrl = new ReactiveObject<>(){};

@Reactive(targetUid = "trackTitle", property = "text", initiativeSync = true)
public ReactiveObject<String> trackTitleText = new ReactiveObject<>(){};

@Override
public void start()
{
albumImageUrl.set("https://media.forgecdn.net/avatars/thumbnails/1071/348/256/256/638606872011907048.png");
activeSetter.invoke(false);
EventCenter.spotifyOverlayEvent.addListener((flag) ->
{
if (flag)
{
activeSetter.invoke(true);
trackTitleText.set("Please wait...");
CompletableFuture.supplyAsync(() ->
{
try
{
TrackPlaying trackPlaying = SpotifyAccessUtils.getCurrentlyPlaying(SpotifyUserInfo.token.accessToken);
albumImageUrl.set(trackPlaying.albumImage300by300);
trackTitleText.set(trackPlaying.trackName);
}
catch (Exception ignored) { }
return null;
});
}
else
activeSetter.invoke(false);
});

// read refresh token and refresh
File directory = new File("config/ingameinfo/cache");
if (!directory.exists()) directory.mkdirs();
try
{
RandomAccessFile file = new RandomAccessFile("config/ingameinfo/cache/spotify_refresh_token.txt", "rw");
StringBuilder builder = new StringBuilder();
String line = file.readLine();
while (line != null)
{
builder.append(line);
line = file.readLine();
}

String refreshToken = builder.toString();
if (!refreshToken.isEmpty())
{
try
{
SpotifyUserInfo.token.refreshToken = refreshToken;
SpotifyOAuthUtils.refreshAccessToken(SpotifyUserInfo.token);
}
catch (IOException e)
{
file.setLength(0);
}
}

file.close();
}
catch (Exception ignored) { }
}

private float refreshTokenTimer = 0;
@Override
public void onFixedUpdate(double deltaTime)
{
refreshTokenTimer += (float)deltaTime;
if (refreshTokenTimer > 1f)
{
refreshTokenTimer -= 1f;
long timeSpan = Duration.between(SpotifyUserInfo.token.start, LocalDateTime.now()).getSeconds();
if (timeSpan >= (SpotifyUserInfo.token.expiresIn - 5))
{
CompletableFuture.supplyAsync(() ->
{
try
{
SpotifyOAuthUtils.refreshAccessToken(SpotifyUserInfo.token);
}
catch (Exception ignored) { }
return null;
});
}
}
}
}
Loading

0 comments on commit 2b3eca1

Please sign in to comment.