2018-07-06 13:30:00 +00:00
package com.eu.habbo.habbohotel.items ;
import com.eu.habbo.Emulator ;
2019-06-10 18:47:39 +03:00
import com.google.gson.JsonArray ;
import com.google.gson.JsonElement ;
import com.google.gson.JsonObject ;
import com.google.gson.JsonParser ;
2018-07-06 13:30:00 +00:00
import gnu.trove.map.hash.THashMap ;
2020-05-04 22:24:09 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2018-07-06 13:30:00 +00:00
2019-06-10 18:47:39 +03:00
import javax.net.ssl.HttpsURLConnection ;
import java.io.BufferedReader ;
2022-03-02 22:13:56 +00:00
import java.io.IOException ;
2019-06-10 18:47:39 +03:00
import java.io.InputStream ;
import java.io.InputStreamReader ;
import java.net.URL ;
import java.sql.* ;
2022-03-02 22:13:56 +00:00
import java.time.Duration ;
2018-07-06 13:30:00 +00:00
import java.util.ArrayList ;
2019-06-10 18:47:39 +03:00
import java.util.concurrent.ExecutorService ;
import java.util.concurrent.Executors ;
import java.util.concurrent.TimeUnit ;
2018-07-06 13:30:00 +00:00
2019-05-26 21:14:53 +03:00
public class YoutubeManager {
2020-05-04 22:24:09 +02:00
private static final Logger LOGGER = LoggerFactory . getLogger ( YoutubeManager . class ) ;
2022-03-02 22:13:56 +00:00
public static class YoutubeVideo {
2019-06-10 18:47:39 +03:00
private final String id ;
private final int duration ;
YoutubeVideo ( String id , int duration ) {
this . id = id ;
this . duration = duration ;
}
public String getId ( ) {
return id ;
}
public int getDuration ( ) {
return duration ;
}
}
2022-03-02 22:13:56 +00:00
public static class YoutubePlaylist {
2019-06-10 18:47:39 +03:00
private final String id ;
private final String name ;
private final String description ;
private final ArrayList < YoutubeVideo > videos ;
YoutubePlaylist ( String id , String name , String description , ArrayList < YoutubeVideo > videos ) {
this . id = id ;
this . name = name ;
this . description = description ;
this . videos = videos ;
}
public String getId ( ) {
return id ;
}
public String getName ( ) {
return name ;
}
public String getDescription ( ) {
return description ;
}
public ArrayList < YoutubeVideo > getVideos ( ) {
return videos ;
}
}
2022-03-02 22:13:56 +00:00
private final THashMap < Integer , ArrayList < YoutubePlaylist > > playlists = new THashMap < > ( ) ;
private final THashMap < String , YoutubePlaylist > playlistCache = new THashMap < > ( ) ;
private final String apiKey = Emulator . getConfig ( ) . getValue ( " youtube.apikey " ) ;
2018-07-06 13:30:00 +00:00
2019-05-26 21:14:53 +03:00
public void load ( ) {
2019-06-10 18:47:39 +03:00
this . playlists . clear ( ) ;
this . playlistCache . clear ( ) ;
2018-07-06 13:30:00 +00:00
2019-06-10 18:47:39 +03:00
long millis = System . currentTimeMillis ( ) ;
2020-02-27 19:48:17 +02:00
Emulator . getThreading ( ) . run ( ( ) - > {
ExecutorService youtubeDataLoaderPool = Executors . newFixedThreadPool ( 10 ) ;
2020-05-04 22:24:09 +02:00
LOGGER . info ( " YouTube Manager -> Loading... " ) ;
2020-02-27 19:48:17 +02:00
try ( Connection connection = Emulator . getDatabase ( ) . getDataSource ( ) . getConnection ( ) ; PreparedStatement statement = connection . prepareStatement ( " SELECT * FROM youtube_playlists " ) ) {
try ( ResultSet set = statement . executeQuery ( ) ) {
while ( set . next ( ) ) {
final int itemId = set . getInt ( " item_id " ) ;
final String playlistId = set . getString ( " playlist_id " ) ;
youtubeDataLoaderPool . submit ( ( ) - > {
ArrayList < YoutubePlaylist > playlists = this . playlists . getOrDefault ( itemId , new ArrayList < > ( ) ) ;
2022-03-02 22:13:56 +00:00
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 ) ;
2020-02-27 19:48:17 +02:00
}
this . playlists . put ( itemId , playlists ) ;
} ) ;
}
2018-07-06 13:30:00 +00:00
}
2020-02-27 19:48:17 +02:00
} catch ( SQLException e ) {
2020-05-04 22:24:09 +02:00
LOGGER . error ( " Caught SQL exception " , e ) ;
2018-07-06 13:30:00 +00:00
}
2020-02-27 19:48:17 +02:00
youtubeDataLoaderPool . shutdown ( ) ;
try {
youtubeDataLoaderPool . awaitTermination ( 60 , TimeUnit . SECONDS ) ;
} catch ( InterruptedException e ) {
e . printStackTrace ( ) ;
}
2018-07-06 13:30:00 +00:00
2020-05-04 22:24:09 +02:00
LOGGER . info ( " YouTube Manager -> Loaded! ( " + ( System . currentTimeMillis ( ) - millis ) + " MS) " ) ;
2020-02-27 19:48:17 +02:00
} ) ;
2018-07-06 13:30:00 +00:00
}
2022-03-02 22:13:56 +00:00
public YoutubePlaylist getPlaylistDataById ( String playlistId ) throws IOException {
2019-06-16 14:44:20 +03:00
if ( this . playlistCache . containsKey ( playlistId ) ) return this . playlistCache . get ( playlistId ) ;
2022-03-02 22:13:56 +00:00
if ( apiKey . isEmpty ( ) ) return null ;
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 ) ;
JsonObject playlistData = JsonParser . parseReader ( playlistBR ) . getAsJsonObject ( ) ;
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 ( ) ;
2019-06-16 14:44:20 +03:00
2022-03-02 22:13:56 +00:00
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 ) ;
}
2018-07-06 13:30:00 +00:00
2022-03-02 22:13:56 +00:00
HttpsURLConnection con = ( HttpsURLConnection ) playlistItems . openConnection ( ) ;
2019-06-10 18:47:39 +03:00
2022-03-02 22:13:56 +00:00
InputStream is = con . getInputStream ( ) ;
2019-06-10 18:47:39 +03:00
InputStreamReader isr = new InputStreamReader ( is ) ;
2022-03-02 22:13:56 +00:00
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 ( ) ) ;
2018-07-06 13:30:00 +00:00
}
2022-03-02 22:13:56 +00:00
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 ) ;
2019-06-16 14:44:20 +03:00
2022-03-02 22:13:56 +00:00
if ( videos . isEmpty ( ) ) {
LOGGER . warn ( " Playlist {} has no videos! " , playlistId ) ;
return null ;
2018-07-06 13:30:00 +00:00
}
2022-03-02 22:13:56 +00:00
playlist = new YoutubePlaylist ( playlistId , name , description , videos ) ;
this . playlistCache . put ( playlistId , playlist ) ;
return playlist ;
2018-07-06 13:30:00 +00:00
}
2019-06-10 18:47:39 +03:00
public ArrayList < YoutubePlaylist > getPlaylistsForItemId ( int itemId ) {
return this . playlists . get ( itemId ) ;
2018-07-06 13:30:00 +00:00
}
2019-06-16 14:44:20 +03:00
public void addPlaylistToItem ( int itemId , YoutubePlaylist playlist ) {
this . playlists . computeIfAbsent ( itemId , k - > new ArrayList < > ( ) ) . add ( playlist ) ;
}
2018-07-06 13:30:00 +00:00
}