hyperdefined

hyperdefined

Downloading Media From Newgrounds

24 July 2024 - 1 minute

How to download videos & music from Newgrounds with magic.

Newgrounds is great site to see classic old internet history in the form of videos & music. Recently, I’ve decided to take on the task of adding support for Newgrounds media to cobalt. Here is how I was able to read Newgrounds pages to find media.


Videos

Let’s use this test video here: https://www.newgrounds.com/portal/view/938050. I first decided to see my browser’s network tab, and clicking play shows this interesting request.

It looks like when you play a video, Newgrounds fetches this URL (noticed how view changed into video) to see playback information. Interesting enough, we need to pass in the header X-Requested-With: XMLHttpRequest. If you do not pass in this header, you will not get back a JSON response. Let’s see what contents it has:

{
    "id": 938050,
    "title": "mmm... beeEEeeRrrr",
    "author": "DonkTK",
    "sources": {
        "1080p": [
            {
                "type": "video\/mp4",
                "src": "https:\/\/uploads.ungrounded.net\/alternate\/5847000\/5847247_alternate_270656.1080p.mp4?1720232179"
            }
        ],
        "720p": [
            {
                "type": "video\/mp4",
                "src": "https:\/\/uploads.ungrounded.net\/alternate\/5847000\/5847247_alternate_270656.720p.mp4?1720232179"
            }
        ],
        "360p": [
            {
                "type": "video\/mp4",
                "src": "https:\/\/uploads.ungrounded.net\/alternate\/5847000\/5847247_alternate_270656.360p.mp4?1720232179"
            }
        ]
    }
}

Perfect, we can see where the video is hosted and the qualities the video offers. Visiting any of the links in this request takes you to the direct video.

Audio

For this example, I am going to use this song: https://www.newgrounds.com/audio/listen/500476. Handling audio downloads is a bit more tricky. However, inspecting the source code of an audio page reveals this interesting section:

<script>
	var embed_controller = new embedController([{
		"url": "https:\/\/audio.ngfiles.com\/500000\/500476_Stereo-Madness.mp3?f1355466273",
		"is_published": true,
		"portal_id": 2,
		"file_id": 0,
		"project_id": 599992,
		"item_id": 500476,
		"description": "Audio File",
		"width": null,
		"height": null,
		"filesize": 7922486,
		"params": {
			"filename": "https:\/\/audio.ngfiles.com\/500000\/500476_Stereo-Madness.mp3?f1355466273",
			"name": "Stereo%20Madness",
			"length": "199",
			"loop": 0,
			"artist": "ForeverBound",
			"icon": "https:\/\/aicon.ngfiles.com\/500\/500476.png?f1364657339",
			"images": {
				"condensed": {
					"completed": {
						"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png",
						"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png"
					},
					"playing": {
						"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png",
						"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png"
					}
				},
				"listen": {
					"completed": {
						"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png",
						"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png"
					},
					"playing": {
						"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png",
						"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png"
					}
				}
			},
			"duration": 199
		},
		"portal_item_requirements": [5],
		"html": "\n\n<div id=\"audio-listen-player\" class=\"audio-listen-player\">\n\t<div id=\"audio-listen-wrapper\" class=\"audio-listen-wrapper\">\n\n\t\t<div id=\"waveform\" class=\"audio-listen-container\"><\/div>\n\n\t\t<div class=\"outer-frame\"><\/div>\n\n\t\t<p id=\"cant-play-mp3\" style=\"display:none\">Your Browser does not support html5\/mp3 audio playback.!!!<\/p>\n\n\t\t<p id=\"loading-audio\">\n\t\t\t<em class=\"fa fa-spin fa-spinner\"><\/em> LOADING...\n\t\t<\/p>\n\t<\/div>\n\n\t<div class=\"audio-listen-controls\">\n\t\t<div class=\"play-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-play\" disabled>\n\t\t\t\t<i class=\"fa fa-play\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-pause\" disabled>\n\t\t\t\t<i class=\"fa fa-pause\"><\/i>\n\t\t\t<\/button>\n\n\t\t<\/div>\n\t\t<div class=\"playback-info\">\n\t\t\t<span id=\"audio-listen-progress\">00.00<\/span>\n\t\t\t\/\n\t\t\t<span id=\"audio-listen-duration\">00.00<\/span>\n\t\t<\/div>\n\t\t<div class=\"sound-controls\">\n\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-repeat\">\n\t\t\t\t<i class=\"fa fa-retweet\"><\/i>\n\t\t\t<\/button>\n\n\t\t\t\t\t\t\t<button class=\"audio-listen-btn\" id=\"audio-listen-volumeToggle\">\n\t\t\t\t\t<i class=\"fa fa-volume-off\"><\/i>\n\t\t\t\t<\/button>\n\n\t\t\t\t<div class=\"off\" id=\"audio-listen-volume\"><\/div>\n\t\t\t\n\t\t<\/div>\n\t<\/div>\n<\/div>\n\n",
		callback: function() {
			(function($) {
				var player = NgAudioPlayer.fromListenPage({
					'generic_id': 500476,
					'type_id': 3,
					'url': "https:\/\/audio.ngfiles.com\/500000\/500476_Stereo-Madness.mp3?f1355466273",
					'version': 1355466273,
					'duration': 199,
					'loop': false,
					'images': {
						"condensed": {
							"completed": {
								"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png",
								"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png"
							},
							"playing": {
								"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png",
								"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png"
							}
						},
						"listen": {
							"completed": {
								"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png",
								"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png"
							},
							"playing": {
								"url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png",
								"rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png"
							}
						}
					},
					'playlist': 'listen'
				}, 128);
			})(jQuery);
		}
	}], null, false, true);
</script>

In short, this script builds the media player’s metadata. The section we want to look at is the params object in this JSON.

"params": {
    "filename": "https:\/\/audio.ngfiles.com\/500000\/500476_Stereo-Madness.mp3?f1355466273",
    "name": "Stereo%20Madness",
    "length": "199",
    "loop": 0,
    "artist": "ForeverBound",
    "icon": "https:\/\/aicon.ngfiles.com\/500\/500476.png?f1364657339",
    "images": {
      "condensed": {
        "completed": {
          "url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png",
          "rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.completed.png"
        },
        "playing": {
          "url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png",
          "rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.condensed.png"
        }
      },
      "listen": {
        "completed": {
          "url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png",
          "rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.completed.png"
        },
        "playing": {
          "url": "\/\/img.ngfiles.com\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png",
          "rel_path": "img\/audio_peaks\/3\/500000\/500476.1355466273-1129.listen.png"
        }
      }
    },
    "duration": 199
}

As you can see, the direct link to this file is the filename key. Visiting the link reveals the direct mp3 file to listen or download.

Conclusion

This was a cool experiment to see how Newgrounds media is handled for cobalt. It was a lot of fun trying and having fun with this side project.