diff --git a/pom.xml b/pom.xml
index 419c9bea..ee824fe4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -106,7 +106,7 @@
mysql
mysql-connector-java
- 5.1.49
+ 8.0.22
runtime
diff --git a/sqlupdates/3_0_0 to 3_0_1.sql b/sqlupdates/3_0_0 to 3_0_1.sql
index a493191f..a5b43fe0 100644
--- a/sqlupdates/3_0_0 to 3_0_1.sql
+++ b/sqlupdates/3_0_0 to 3_0_1.sql
@@ -6,6 +6,9 @@ INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.error.cmd_stalk.
-- Enable or Disable TTY in console (Default is enabled)
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('console.mode', '1');
+-- Youtube Api v3 key to YoutubeManager
+INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('youtube.apikey', '');
+
-- ----------------------------
-- Table structure for calendar_campaigns
-- ----------------------------
@@ -46,7 +49,7 @@ CREATE TABLE `calendar_rewards` (
`subscription_days` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
);
-@ -92,11 +92,12 @@
+
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('hotel.calendar.default', 'test');
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('hotel.calendar.pixels.hc_modifier', '2.0');
@@ -56,4 +59,4 @@ ALTER TABLE `permissions` ADD COLUMN `acc_calendar_force` enum('0','1') NULL DEF
-- UpdateCalendar command.
ALTER TABLE `permissions` ADD `cmd_update_calendar` ENUM('0', '1') NOT NULL DEFAULT '0';
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.description.cmd_update_calendar', ':update_calendar'), ('commands.keys.cmd_update_calendar', 'update_calendar');
-INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.success.cmd_update_calendar', 'Calendar updated successfully!');
\ No newline at end of file
+INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.success.cmd_update_calendar', 'Calendar updated successfully!');
diff --git a/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java b/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java
index a48aad2f..3e543e0c 100644
--- a/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java
+++ b/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java
@@ -504,7 +504,6 @@ public class CatalogManager {
return null;
}
-
public Voucher getVoucher(String code) {
synchronized (this.vouchers) {
for (Voucher voucher : this.vouchers) {
@@ -516,22 +515,20 @@ public class CatalogManager {
return null;
}
-
public void redeemVoucher(GameClient client, String voucherCode) {
- Voucher voucher = Emulator.getGameEnvironment().getCatalogManager().getVoucher(voucherCode);
+ Habbo habbo = client.getHabbo();
+ if (habbo == null)
+ return;
+ Voucher voucher = Emulator.getGameEnvironment().getCatalogManager().getVoucher(voucherCode);
if (voucher == null) {
client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.INVALID_CODE));
return;
}
- Habbo habbo = client.getHabbo();
- if (habbo == null) return;
-
if (voucher.isExhausted()) {
- if (!Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher)) {
- client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.TECHNICAL_ERROR));
- }
+ client.sendResponse(new RedeemVoucherErrorComposer(Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher) ? RedeemVoucherErrorComposer.INVALID_CODE : RedeemVoucherErrorComposer.TECHNICAL_ERROR));
+ return;
}
if (voucher.hasUserExhausted(habbo.getHabboInfo().getId())) {
@@ -541,12 +538,6 @@ public class CatalogManager {
voucher.addHistoryEntry(habbo.getHabboInfo().getId());
- if (voucher.isExhausted()) {
- if (!Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher)) {
- client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.TECHNICAL_ERROR));
- }
- }
-
if (voucher.points > 0) {
client.getHabbo().getHabboInfo().addCurrencyAmount(voucher.pointsType, voucher.points);
client.sendResponse(new UserPointsComposer(client.getHabbo().getHabboInfo().getCurrencyAmount(voucher.pointsType), voucher.points, voucher.pointsType));
@@ -559,7 +550,6 @@ public class CatalogManager {
if (voucher.catalogItemId > 0) {
CatalogItem item = this.getCatalogItem(voucher.catalogItemId);
-
if (item != null) {
this.purchaseItem(null, item, client.getHabbo(), 1, "", true);
}
@@ -568,7 +558,6 @@ public class CatalogManager {
client.sendResponse(new RedeemVoucherOKComposer());
}
-
public boolean deleteVoucher(Voucher voucher) {
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("DELETE FROM vouchers WHERE code = ?")) {
statement.setString(1, voucher.code);
diff --git a/src/main/java/com/eu/habbo/habbohotel/items/YoutubeManager.java b/src/main/java/com/eu/habbo/habbohotel/items/YoutubeManager.java
index 3be71726..a383541a 100644
--- a/src/main/java/com/eu/habbo/habbohotel/items/YoutubeManager.java
+++ b/src/main/java/com/eu/habbo/habbohotel/items/YoutubeManager.java
@@ -11,10 +11,12 @@ import org.slf4j.LoggerFactory;
import javax.net.ssl.HttpsURLConnection;
import java.io.BufferedReader;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.sql.*;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -23,7 +25,7 @@ import java.util.concurrent.TimeUnit;
public class YoutubeManager {
private static final Logger LOGGER = LoggerFactory.getLogger(YoutubeManager.class);
- public class YoutubeVideo {
+ public static class YoutubeVideo {
private final String id;
private final int duration;
@@ -41,7 +43,7 @@ public class YoutubeManager {
}
}
- public class YoutubePlaylist {
+ public static class YoutubePlaylist {
private final String id;
private final String name;
private final String description;
@@ -71,8 +73,9 @@ public class YoutubeManager {
}
}
- private THashMap> playlists = new THashMap<>();
- private THashMap playlistCache = new THashMap<>();
+ private final THashMap> playlists = new THashMap<>();
+ private final THashMap playlistCache = new THashMap<>();
+ private final String apiKey = Emulator.getConfig().getValue("youtube.apikey");
public void load() {
this.playlists.clear();
@@ -94,11 +97,15 @@ public class YoutubeManager {
youtubeDataLoaderPool.submit(() -> {
ArrayList playlists = this.playlists.getOrDefault(itemId, new ArrayList<>());
- YoutubePlaylist playlist = this.getPlaylistDataById(playlistId);
- if (playlist != null) {
- playlists.add(playlist);
- } else {
- LOGGER.error("Failed to load YouTube playlist: " + playlistId);
+ YoutubePlaylist playlist;
+
+ try {
+ playlist = this.getPlaylistDataById(playlistId);
+ if (playlist != null) {
+ playlists.add(playlist);
+ }
+ } catch (IOException e) {
+ LOGGER.error("Failed to load YouTube playlist {} ERROR: {}", playlistId, e);
}
this.playlists.put(itemId, playlists);
@@ -120,56 +127,102 @@ public class YoutubeManager {
});
}
- public YoutubePlaylist getPlaylistDataById(String playlistId) {
+ public YoutubePlaylist getPlaylistDataById(String playlistId) throws IOException {
if (this.playlistCache.containsKey(playlistId)) return this.playlistCache.get(playlistId);
+ if(apiKey.isEmpty()) return null;
- try {
- URL myUrl = new URL("https://www.youtube.com/playlist?list=" + playlistId);
+ YoutubePlaylist playlist;
+ URL playlistInfo = new URL("https://youtube.googleapis.com/youtube/v3/playlists?part=snippet&id=" + playlistId + "&maxResults=1&key=" + apiKey);
+ HttpsURLConnection playlistCon = (HttpsURLConnection) playlistInfo.openConnection();
+ if (playlistCon.getResponseCode() != 200) {
+ InputStream errorInputStream = playlistCon.getErrorStream();
+ InputStreamReader playlistISR = new InputStreamReader(errorInputStream);
+ BufferedReader playlistBR = new BufferedReader(playlistISR);
+ JsonObject errorObj = JsonParser.parseReader(playlistBR).getAsJsonObject();
+ String message = errorObj.get("error").getAsJsonObject().get("message").getAsString();
+ LOGGER.error("Failed to load YouTube playlist {} ERROR: {}", playlistId, message);
+ return null;
+ }
+ InputStream playlistInputStream = playlistCon.getInputStream();
+ InputStreamReader playlistISR = new InputStreamReader(playlistInputStream);
+ BufferedReader playlistBR = new BufferedReader(playlistISR);
- HttpsURLConnection conn = (HttpsURLConnection) myUrl.openConnection();
- conn.setRequestProperty("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3");
- conn.setRequestProperty("accept-language", "en-GB,en-US;q=0.9,en;q=0.8");
- conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3731.0 Safari/537.36");
+ JsonObject playlistData = JsonParser.parseReader(playlistBR).getAsJsonObject();
- InputStream is = conn.getInputStream();
- InputStreamReader isr = new InputStreamReader(is);
- YoutubePlaylist playlist;
- try (BufferedReader br = new BufferedReader(isr)) {
- playlist = null;
- String inputLine;
- while ((inputLine = br.readLine()) != null) {
- if (inputLine.contains("window[\"ytInitialData\"]")) {
- JsonObject obj = new JsonParser().parse(inputLine.substring(inputLine.indexOf("{")).replace(";", "")).getAsJsonObject();
-
- JsonObject meta = obj.get("microformat").getAsJsonObject().get("microformatDataRenderer").getAsJsonObject();
- String name = meta.get("title").getAsString();
- String description = meta.get("description").getAsString();
-
- ArrayList videos = new ArrayList<>();
-
- JsonArray rawVideos = obj.get("contents").getAsJsonObject().get("twoColumnBrowseResultsRenderer").getAsJsonObject().get("tabs").getAsJsonArray().get(0).getAsJsonObject().get("tabRenderer").getAsJsonObject().get("content").getAsJsonObject().get("sectionListRenderer").getAsJsonObject().get("contents").getAsJsonArray().get(0).getAsJsonObject().get("itemSectionRenderer").getAsJsonObject().get("contents").getAsJsonArray().get(0).getAsJsonObject().get("playlistVideoListRenderer").getAsJsonObject().get("contents").getAsJsonArray();
-
- for (JsonElement rawVideo : rawVideos) {
- JsonObject videoData = rawVideo.getAsJsonObject().get("playlistVideoRenderer").getAsJsonObject();
- if (!videoData.has("lengthSeconds")) continue; // removed videos
- videos.add(new YoutubeVideo(videoData.get("videoId").getAsString(), Integer.valueOf(videoData.get("lengthSeconds").getAsString())));
- }
-
- playlist = new YoutubePlaylist(playlistId, name, description, videos);
-
- break;
- }
- }
+ JsonArray playlists = playlistData.get("items").getAsJsonArray();
+ if (playlists.size() == 0) {
+ LOGGER.error("Playlist {} not found!", playlistId);
+ return null;
+ }
+ JsonObject playlistItem = playlists.get(0).getAsJsonObject().get("snippet").getAsJsonObject();
+
+ String name = playlistItem.get("title").getAsString();
+ String description = playlistItem.get("description").getAsString();
+
+ ArrayList < YoutubeVideo > videos = new ArrayList < > ();
+ String nextPageToken = "";
+ do {
+ ArrayList < String > videoIds = new ArrayList < > ();
+ URL playlistItems;
+
+ if (nextPageToken.isEmpty()) {
+ playlistItems = new URL("https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet%2Cstatus&playlistId=" + playlistId + "&maxResults=50&key=" + apiKey);
+ } else {
+ playlistItems = new URL("https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet%2Cstatus&playlistId=" + playlistId + "&pageToken=" + nextPageToken + "&maxResults=50&key=" + apiKey);
}
- this.playlistCache.put(playlistId, playlist);
+ HttpsURLConnection con = (HttpsURLConnection) playlistItems.openConnection();
- return playlist;
- } catch (java.io.IOException e) {
- e.printStackTrace();
+ InputStream is = con.getInputStream();
+ InputStreamReader isr = new InputStreamReader(is);
+ BufferedReader br = new BufferedReader(isr);
+ JsonObject object = JsonParser.parseReader(br).getAsJsonObject();
+
+ JsonArray rawV = object.get("items").getAsJsonArray();
+ for (JsonElement rawVideo: rawV) {
+ JsonObject videoData = rawVideo.getAsJsonObject().get("snippet").getAsJsonObject();
+ JsonObject videoStatus = rawVideo.getAsJsonObject().get("status").getAsJsonObject();
+ if (!videoStatus.get("privacyStatus").getAsString().equals("public"))
+ continue; // removed videos
+ videoIds.add(videoData.get("resourceId").getAsJsonObject().get("videoId").getAsString());
+ }
+
+ if (!videoIds.isEmpty()) {
+ URL VideoItems;
+
+ String commaSeparatedVideos = String.join(",", videoIds);
+
+ VideoItems = new URL("https://youtube.googleapis.com/youtube/v3/videos?part=contentDetails&id=" + commaSeparatedVideos + "&maxResults=50&key=" + apiKey);
+ HttpsURLConnection con1 = (HttpsURLConnection) VideoItems.openConnection();
+ InputStream is1 = con1.getInputStream();
+ InputStreamReader isr1 = new InputStreamReader(is1);
+ BufferedReader br1 = new BufferedReader(isr1);
+ JsonObject object1 = JsonParser.parseReader(br1).getAsJsonObject();
+ JsonArray Vds = object1.get("items").getAsJsonArray();
+ for (JsonElement rawVideo: Vds) {
+ JsonObject contentDetails = rawVideo.getAsJsonObject().get("contentDetails").getAsJsonObject();
+ int duration = (int) Duration.parse(contentDetails.get("duration").getAsString()).getSeconds();
+ if (duration < 1) continue;
+ videos.add(new YoutubeVideo(rawVideo.getAsJsonObject().get("id").getAsString(), duration));
+ }
+ }
+ if (object.has("nextPageToken")) {
+ nextPageToken = object.get("nextPageToken").getAsString();
+ } else {
+ nextPageToken = null;
+ }
+ } while (nextPageToken != null);
+
+ if (videos.isEmpty()) {
+ LOGGER.warn("Playlist {} has no videos!", playlistId);
+ return null;
}
+ playlist = new YoutubePlaylist(playlistId, name, description, videos);
+
+ this.playlistCache.put(playlistId, playlist);
+
+ return playlist;
- return null;
}
public ArrayList getPlaylistsForItemId(int itemId) {
diff --git a/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java b/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java
index 2a65ba4a..3b8e5b3b 100644
--- a/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java
+++ b/src/main/java/com/eu/habbo/habbohotel/modtool/ModToolManager.java
@@ -184,8 +184,6 @@ public class ModToolManager {
public void quickTicket(Habbo reported, String reason, String message) {
ModToolIssue issue = new ModToolIssue(0, reason, reported.getHabboInfo().getId(), reported.getHabboInfo().getUsername(), 0, message, ModToolTicketType.AUTOMATIC);
- if (Emulator.getPluginManager().fireEvent(new SupportTicketEvent(null, issue)).isCancelled())
- return;
Emulator.getGameEnvironment().getModToolManager().addTicket(issue);
Emulator.getGameEnvironment().getModToolManager().updateTicketToMods(issue);
diff --git a/src/main/java/com/eu/habbo/habbohotel/users/HabboStats.java b/src/main/java/com/eu/habbo/habbohotel/users/HabboStats.java
index 64747a29..462af849 100644
--- a/src/main/java/com/eu/habbo/habbohotel/users/HabboStats.java
+++ b/src/main/java/com/eu/habbo/habbohotel/users/HabboStats.java
@@ -269,7 +269,7 @@ public class HabboStats implements Runnable {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM users_settings WHERE user_id = ? LIMIT 1")) {
statement.setInt(1, habboInfo.getId());
try (ResultSet set = statement.executeQuery()) {
- set.first();
+ set.next();
if (set.getRow() != 0) {
stats = new HabboStats(set, habboInfo);
} else {
diff --git a/src/main/java/com/eu/habbo/messages/incoming/rooms/items/youtube/YoutubeRequestStateChange.java b/src/main/java/com/eu/habbo/messages/incoming/rooms/items/youtube/YoutubeRequestStateChange.java
index f212e698..b9010e5a 100644
--- a/src/main/java/com/eu/habbo/messages/incoming/rooms/items/youtube/YoutubeRequestStateChange.java
+++ b/src/main/java/com/eu/habbo/messages/incoming/rooms/items/youtube/YoutubeRequestStateChange.java
@@ -64,10 +64,12 @@ public class YoutubeRequestStateChange extends MessageHandler {
HabboItem item = this.client.getHabbo().getHabboInfo().getCurrentRoom().getHabboItem(itemId);
- if (item == null || !(item instanceof InteractionYoutubeTV)) return;
+ if (!(item instanceof InteractionYoutubeTV)) return;
InteractionYoutubeTV tv = (InteractionYoutubeTV) item;
+ if(tv.currentPlaylist == null || tv.currentPlaylist.getVideos().isEmpty()) return;
+
switch (state) {
case PAUSE:
tv.playing = false;
@@ -104,4 +106,4 @@ public class YoutubeRequestStateChange extends MessageHandler {
room.updateItem(tv);
}
}
-}
\ No newline at end of file
+}