Skip to content

Instantly share code, notes, and snippets.

@haze
Last active January 8, 2017 20:17
Show Gist options
  • Save haze/4af7a3be79abc0038dbce60a6719d92b to your computer and use it in GitHub Desktop.
Save haze/4af7a3be79abc0038dbce60a6719d92b to your computer and use it in GitHub Desktop.
1 class API for Genius ( needs Jsoup and Apache HTTP components )
package pw.haze.lyribot
import com.github.salomonbrys.kotson.fromJson
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpUriRequest
import org.apache.http.impl.client.HttpClientBuilder
import org.jsoup.Jsoup
import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.URLEncoder
/**
* @author Haze
* @time 11:35 (11:35 AM)
* @since 1/1/2017
*/
private val chromeUserAgent: String = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.28 Safari/537.36"
// f*** genius and f*** jsoup worst combination ever smfhtbqbh
fun <T> List<T>.skip(n: Int): List<T> = subList(n, size)
private fun scrapeLyrics(url: String): Array<String> = Jsoup.connect(url).userAgent(chromeUserAgent).get().getElementsByTag("lyrics").first().text().split("[").skip(1).map { s -> "[$s" }.toTypedArray()
class Genius(val id: String, val secret: String, val clientToken: String) {
// General Specifications
data class MetaObject(val status: Int)
data class Album(@SerializedName("api_path") val apiPath: String,
@SerializedName("cover_art_url") val coverArtURL: String,
val id: Long,
val name: String,
val url: String,
val artist: Artist)
data class MediaObject(val cinema: Boolean,
val provider: String,
val start: Int,
val type: String,
val url: String)
data class Song(val hot: Boolean,
@SerializedName("unreviewed_annotations") val unreviewedAnnotations: Int,
@SerializedName("pageviews") val pageViews: Int,
@SerializedName("annotation_count") val annotations: Int,
@SerializedName("api_path") val apiPath: String,
@SerializedName("featured_video") val featuredVideo: Boolean,
@SerializedName("full_title") val fullTitle: String,
@SerializedName("lyrics_owner_id") val lyricsOwnerID: Int,
@SerializedName("pyongs_count") val pyongs: Int,
@SerializedName("recording_location") val recordingLocation: String,
@SerializedName("release_date") val releaseDate: String,
@SerializedName("song_art_image_thumbnail_url") val songArtImageThumbURL: String,
@SerializedName("song_art_image_url") val songArtImageURL: String,
@SerializedName("primary_artist") val primaryArtist: Artist,
@SerializedName("writer_artists") val writers: Array<Artist>,
val url: String,
val id: Long,
val title: String,
val album: Album,
val media: Array<MediaObject>,
val concurrents: Int
) {
val lyrics: Array<String>
get() = scrapeLyrics(this.url)
}
data class Artist(@SerializedName("api_path") val apiPath: String,
@SerializedName("alternative_names") val alternativeNames: Array<String>,
@SerializedName("facebook_name") val facebookName: String,
@SerializedName("followers_count") val followers: Int,
@SerializedName("instagram_name") val instagramName: String,
@SerializedName("twitter_name") val twitterName: String,
@SerializedName("header_image_url") val headerImageURL: String,
val id: Long,
@SerializedName("image_url") val imageURL: String,
@SerializedName("is_meme_verified") val isMeme: Boolean,
@SerializedName("is_verified") val isVerified: Boolean,
val name: String,
val url: String,
val iq: Int)
// Search Specifications
// *NOTE* I've ignored the "highlights" tag as it appeared to return nothing from the example search query.
data class SearchIndex(@SerializedName("annotation_count") val annotations: Int,
@SerializedName("api_path") val apiPath: String,
@SerializedName("full_title") val fullTitle: String,
@SerializedName("header_image_thumbnail_url") val headerThumbImageURL: String,
@SerializedName("header_image_url") val headerImageURl: String,
@SerializedName("lyrics_owner_id") val ownerID: Int,
val id: Long,
val path: String,
@SerializedName("pyongs") val pyongs: Int,
@SerializedName("song_art_image_thumbnail_url") val songArtImageThumbURL: String,
val title: String,
val url: String,
@SerializedName("primary_artist") val primaryArtist: Artist)
data class SearchHit(val index: String, val type: String, val result: SearchIndex)
data class SearchResult(val hits: Array<SearchHit>)
data class SongResult(val song: Song)
// query meta wrappers
data class ArtistQuery(val meta: MetaObject, val response: Artist)
data class SearchQuery(val meta: MetaObject, val response: SearchResult)
data class SongQuery(val meta: MetaObject, val response: SongResult)
private val gson: Gson = Gson()
private val apiEndpoint: String = "http://api.genius.com/"
private val authString: String = "Bearer $clientToken"
private fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8")
private fun HttpUriRequest.addGeniusHeaders(): HttpUriRequest = apply { addHeader("Host", "api.genius.com"); addHeader("User-Agent", chromeUserAgent); addHeader("Accept", "application/json"); addHeader("Authorization", authString) }
fun search(query: String): SearchQuery = gson.fromJson<SearchQuery>(BufferedReader(InputStreamReader(HttpClientBuilder.create().build().execute(HttpGet("${this.apiEndpoint}search?q=${query.urlEncode()}").addGeniusHeaders()).entity.content)))
fun artist(id: Long): ArtistQuery = gson.fromJson<ArtistQuery>(BufferedReader(InputStreamReader(HttpClientBuilder.create().build().execute(HttpGet("${this.apiEndpoint}artists/$id").addGeniusHeaders()).entity.content)))
fun song(id: Long): SongQuery = gson.fromJson<SongQuery>(BufferedReader(InputStreamReader(HttpClientBuilder.create().build().execute(HttpGet("${this.apiEndpoint}songs/$id").addGeniusHeaders()).entity.content)))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment