99
1010import com .dunctebot .sourcemanagers .AbstractDuncteBotHttpSource ;
1111import com .dunctebot .sourcemanagers .tumblr .audio .TumblrBasePostAudioTrack ;
12+ import com .dunctebot .sourcemanagers .tumblr .audio .TumblrMp3AudioTrack ;
1213import com .dunctebot .sourcemanagers .tumblr .audio .TumblrMpegAudioTrack ;
1314import com .sedmelluq .discord .lavaplayer .player .AudioPlayerManager ;
1415import com .sedmelluq .discord .lavaplayer .tools .FriendlyException ;
2425import org .apache .http .client .methods .HttpPost ;
2526import org .apache .http .entity .ContentType ;
2627import org .apache .http .entity .StringEntity ;
28+ import org .slf4j .Logger ;
29+ import org .slf4j .LoggerFactory ;
2730
2831import java .io .DataInput ;
2932import java .io .DataOutput ;
3235import java .util .List ;
3336import java .util .regex .Pattern ;
3437
38+ import static com .dunctebot .sourcemanagers .Utils .USER_AGENT ;
39+
3540public class TumblrAudioSourceManager extends AbstractDuncteBotHttpSource {
3641 private static final Pattern NORMAL_POST_PATTERN = Pattern .compile ("https:\\ /\\ /(?:www\\ .)?tumblr\\ .com\\ /(?<username>[^\\ /]+)\\ /(?<postId>[^\\ /]+)\\ /?.*" );
3742 private static final Pattern BLOG_SUB_PATTERN = Pattern .compile ("https:\\ /\\ /(?<username>[^\\ .]+)\\ .tumblr\\ .com\\ /post\\ /(?<postId>[^\\ /]+)\\ /?.*" );
43+ private static final Logger log = LoggerFactory .getLogger (TumblrAudioSourceManager .class );
3844
39- // TODO: https://tmblr.co/ZWMt9uiVE9gHKi00
45+ // TODO: https://tmblr.co/ZWMt9uiVE9gHKi00 (when I feel like it tbh, nobody uses these links)
4046
4147 private final String oauthConsumerKey ;
4248 private final String oauthSecretKey ;
4349
50+ private long tokenExpiresAt = -1 ;
51+ private String accessToken = null ;
52+
4453 public TumblrAudioSourceManager (String consumerKey , String secretKey ) {
4554 this .oauthConsumerKey = consumerKey ;
4655 this .oauthSecretKey = secretKey ;
@@ -101,12 +110,15 @@ public void encodeTrack(AudioTrack track, DataOutput output) throws IOException
101110 public AudioTrack decodeTrack (AudioTrackInfo trackInfo , DataInput input ) throws IOException {
102111 final var mediaUrl = input .readUTF ();
103112
104- if (trackInfo .identifier .endsWith ("audio/mpeg" )) {
113+ if (trackInfo .uri .endsWith ("audio/mpeg" )) {
114+ return new TumblrMp3AudioTrack (trackInfo , this , mediaUrl );
115+ }
116+
117+ if (trackInfo .uri .endsWith ("video/mp4" )) {
105118 return new TumblrMpegAudioTrack (trackInfo , this , mediaUrl );
106119 }
107120
108- // TODO: this error is wrong
109- throw new FriendlyException ("Unknown post type encountered while decoding tumblr track" , FriendlyException .Severity .COMMON , null );
121+ throw new FriendlyException ("Unknown media type encountered whilst trying to decode tumblr track" , FriendlyException .Severity .COMMON , null );
110122 }
111123
112124 public TumblrBasePostAudioTrack fetchPostData (String username , String postId ) throws Exception {
@@ -149,22 +161,22 @@ public TumblrBasePostAudioTrack postToTrack(JsonBrowser post, String postUrl) {
149161 throw new FriendlyException ("Provider not supported: " + ci .get ("provider" ).text (), FriendlyException .Severity .COMMON , null );
150162 }
151163
152- final var creatorName = post . get ( "blog" ). get ( "title" ). text ( );
164+ final var creatorName = getBlogName ( post );
153165 final var artwork = post .get ("blog" ).get ("avatar" ).index (0 ).get ("url" ).text ();
154166
155167 final var audioType = ci .get ("media" ).get ("type" ).text ();
156168 final var audioUrl = ci .get ("media" ).get ("url" ).text ();
157169 final var audioTitle = ci .get ("title" ).textOrDefault ("Tumblr Audio by " + creatorName );
158170
159171 if (audioType .equals ("audio/mpeg" )) {
160- return new TumblrMpegAudioTrack (
172+ return new TumblrMp3AudioTrack (
161173 new AudioTrackInfo (
162174 audioTitle ,
163175 creatorName ,
164176 Units .CONTENT_LENGTH_UNKNOWN ,
165- postUrl + "?dbextra=" + audioType ,
166- false ,
167177 postUrl ,
178+ false ,
179+ postUrl + "?dbextra=" + audioType ,
168180 artwork ,
169181 null
170182 ),
@@ -173,7 +185,32 @@ public TumblrBasePostAudioTrack postToTrack(JsonBrowser post, String postUrl) {
173185 );
174186 }
175187 } else if ("video" .equals (ci .get ("type" ).text ())) {
176- // TODO
188+ if (!"tumblr" .equals (ci .get ("provider" ).text ())) {
189+ throw new FriendlyException ("Provider not supported: " + ci .get ("provider" ).text (), FriendlyException .Severity .COMMON , null );
190+ }
191+
192+ final var creatorName = getBlogName (post );
193+ final var artwork = post .get ("blog" ).get ("avatar" ).index (0 ).get ("url" ).text ();
194+
195+ final var videoType = ci .get ("media" ).get ("type" ).text ();
196+ final var videoUrl = ci .get ("media" ).get ("url" ).text ();
197+
198+ if (videoType .equals ("video/mp4" )) {
199+ return new TumblrMpegAudioTrack (
200+ new AudioTrackInfo (
201+ "Tumblr Video by " + creatorName ,
202+ creatorName ,
203+ Units .CONTENT_LENGTH_UNKNOWN ,
204+ postUrl ,
205+ false ,
206+ postUrl + "?dbextra=" + videoType ,
207+ artwork ,
208+ null
209+ ),
210+ this ,
211+ videoUrl
212+ );
213+ }
177214 }
178215 }
179216
@@ -192,18 +229,33 @@ public JsonBrowser fetchNPFData(String username, String postId) throws Exception
192229 final var token = this .fetchOAuth2Token ();
193230
194231 httpGet .addHeader ("Authorization" , "Bearer " + token );
232+ httpGet .addHeader ("Accept" , "application/json" );
233+ httpGet .setHeader ("User-Agent" , USER_AGENT );
195234
196235 try (final CloseableHttpResponse res = getHttpInterface ().execute (httpGet )) {
197236 final String content = IOUtils .toString (res .getEntity ().getContent (), StandardCharsets .UTF_8 );
198237
238+ System .out .println (content );
239+
240+ final int statusCode = res .getStatusLine ().getStatusCode ();
241+
242+ if (statusCode != 200 ) {
243+ throw new IOException ("Tumblr api request failed: " + statusCode );
244+ }
245+
199246 return JsonBrowser .parse (content );
200247 }
201248 }
202249
203250 public String fetchOAuth2Token () throws Exception {
251+ if (System .currentTimeMillis () < this .tokenExpiresAt ) {
252+ return this .accessToken ;
253+ }
254+
204255 final var httpPost = new HttpPost ("https://api.tumblr.com/v2/oauth2/token" );
205256
206257 httpPost .addHeader ("Content-Type" , "application/x-www-form-urlencoded" );
258+ httpPost .setHeader ("User-Agent" , USER_AGENT );
207259
208260 final var body = String .join ("&" , List .of (
209261 // Thank you for not documenting this LMAO
@@ -217,9 +269,32 @@ public String fetchOAuth2Token() throws Exception {
217269 );
218270
219271 try (final CloseableHttpResponse res = getHttpInterface ().execute (httpPost )) {
272+ final int statusCode = res .getStatusLine ().getStatusCode ();
273+
274+ if (statusCode != 200 ) {
275+ throw new IOException ("Invalid status for fetching tumblr access token: " + statusCode );
276+ }
277+
220278 final String content = IOUtils .toString (res .getEntity ().getContent (), StandardCharsets .UTF_8 );
221279
222- return JsonBrowser .parse (content ).get ("access_token" ).text ();
280+ System .out .println (content );
281+
282+ final var json = JsonBrowser .parse (content );
283+ this .accessToken = json .get ("access_token" ).text ();
284+ // expires_in is in seconds
285+ this .tokenExpiresAt = System .currentTimeMillis () + (json .get ("expires_in" ).asLong (0L ) * 1000L );
286+
287+ return this .accessToken ;
223288 }
224289 }
290+
291+ private static String getBlogName (JsonBrowser post ) {
292+ final var blogTitle = post .get ("blog" ).get ("title" ).safeText ();
293+
294+ if (blogTitle .isBlank ()) {
295+ return post .get ("blog" ).get ("name" ).text ();
296+ }
297+
298+ return blogTitle ;
299+ }
225300}
0 commit comments