Mediary is a service that can download, convert and upload media
Example use cases:
- Given a magnet link, download files A, B and C, glue them together and upload to this pre-signed S3 URL
- Given a YouTube video link, download audio, convert it to .mp3, and upload to this pre-signed S3 URL
- (to be done) Given a link to a single file, just take it and upload it to this pre-signed S3 URL
GET /metadata
- returns metadata for a given media link. You are going to need it if you want to pick and choose which files should be processed.POST /job
- creates a task to upload media. Describes the source URL, files at source URL to be processed, what transformation to apply and where to upload the result.GET /job/{id}
- returns the status of a job.
By default, the endpoint will time out pretty quickly, probably sooner than it takes to fetch metadata of a torrent, for example.
In such cases, the endpoint will return a 202 Accepted
status code and a message {"status": "accepted"}
Feel free to repeat your request later: metadata is still being fetched in background.
$ curl -X GET '/metadata?url=magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56&tr=http%3A%2F%2Fbt.t-ru.org'
{"status": "accepted"}
In case you'd rather wait for the metadata to be fetched, you can use the long-polling endpoint.
It will not return a response until the metadata is fetched.
There is still a timeout on the request, but it's pretty long (5 minutes).
$ curl -X GET '/metadata/long-polling?url=magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56&tr=http%3A%2F%2Fbt.t-ru.org'
{
"url": "magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56",
"name": "Джо Диспенза - Медитации к Силе подсознания [Александр Шаронов]",
"variants": [
{
"id": "вступление.mp3",
"length_bytes": 1181881
},
{
"id": "глава 1.mp3",
"length_bytes": 1181881
},
{
"id": "глава 2.mp3",
"length_bytes": 1181881
}
],
"allow_multiple_variants": true,
"downloader_name": "torrent"
}
It goes without saying, that once the metadata is fetched, it is cached.
So all consecutive requests for the same URL will return the same metadata, and immediately.
$ curl -X GET '/metadata?url=magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56&tr=http%3A%2F%2Fbt.t-ru.org'
{
"url": "magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56",
"name": "Джо Диспенза - Медитации к Силе подсознания [Александр Шаронов]",
"variants": [
{
"id": "вступление.mp3",
"length_bytes": 1181881
},
{
"id": "глава 1.mp3",
"length_bytes": 1181881
},
{
"id": "глава 2.mp3",
"length_bytes": 1181881
}
],
"allow_multiple_variants": true,
"downloader_name": "torrent"
}
As you could've noticed, in previous calls part of the URL was lost.
To work around it, service also supports POST
requests to /metadata
endpoint.
In this case, you can pass the URL in the JSON body of the request.
$ curl -X POST '/metadata'--data-raw='{"url": "magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56&tr=http%3A%2F%2Fbt.t-ru.org"}'
{
"url": "magnet:?xt=urn:btih:FB0B49D5E3E18E29868C680D2F7BC00D67987D56\u0026tr=http%3A%2F%2Fbt.t-ru.org",
"name": "Джо Диспенза - Медитации к Силе подсознания [Александр Шаронов]",
"variants": [
{
"id": "вступление.mp3",
"length_bytes": 1181881
},
{
"id": "глава 1.mp3",
"length_bytes": 1181881
},
{
"id": "глава 2.mp3",
"length_bytes": 1181881
}
],
"allow_multiple_variants": true,
"downloader_name": "torrent"
}
The endpoint also supports fetching metadata for YouTube videos. Note that instead of file paths we get different options of desired formats: Video, Audio, different qualities, etc.
This will allow you to choose the format you want to download later in the same UI as for torrent files.
Since it does not make sense to concatenate different versions of the same video,
response also will have '"allow_multiple_files": false
.
Take this into account while presenting format options to user
$ curl -X GET '/metadata?url=https://www.youtube.com/watch?v=kPN-uWB28X8'
{"status": "accepted"}
and then later
$ curl -X GET '/metadata?url=https://www.youtube.com/watch?v=kPN-uWB28X8'
{
"url": "https://www.youtube.com/watch?v=kPN-uWB28X8",
"name": "Miles Davis - Baby won't you please come home",
"variants": [
{
"id": "Video (mp4)"
},
{
"id": "Audio (mp3), High Quality"
},
{
"id": "Audio (mp3), Medium Quality"
},
{
"id": "Audio (mp3), Low Quality"
}
],
"allow_multiple_variants": false,
"downloader_name": "ytdl"
}
POST to /jobs
will schedule for background execution a process of downloading, converting/processing and uploading the media.
Only required parameters are url
and type
. type
signifies the type of operation to be performed.
Each operation can require some additional parameters, passed as params
. For example, concatenate
job
requires a list of files to be concatenated and, optionally, an audioCodec
to be used for the output file.
$ curl -X POST '/jobs'--data-raw='{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73&tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"variants": [
"01-001.mp3",
"01-002.mp3"
],
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request&X-Amz-Date=20230916T202904Z&X-Amz-Expires=900&X-Amz-Security-Token=dummy&X-Amz-SignedHeaders=host&x-id=PutObject&X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52"
}
}'
{"status": "accepted", "id": "d530ada48ea0b6f480c077af49f62bc6"}
Since jobs can run for a long time, job creation api responds immediately with a job ID.
To check the status of the job, you can use the /jobs/:id
endpoint.
0s after starting the job:
$ curl -X GET '/jobs/d530ada48ea0b6f480c077af49f62bc6'
{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73\u0026tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request\u0026X-Amz-Date=20230916T202904Z\u0026X-Amz-Expires=900\u0026X-Amz-Security-Token=dummy\u0026X-Amz-SignedHeaders=host\u0026x-id=PutObject\u0026X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52",
"variants": [
"01-001.mp3",
"01-002.mp3"
]
},
"id": "d530ada48ea0b6f480c077af49f62bc6",
"status": "created"
}
1s later:
$ curl -X GET '/jobs/d530ada48ea0b6f480c077af49f62bc6'
{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73\u0026tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request\u0026X-Amz-Date=20230916T202904Z\u0026X-Amz-Expires=900\u0026X-Amz-Security-Token=dummy\u0026X-Amz-SignedHeaders=host\u0026x-id=PutObject\u0026X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52",
"variants": [
"01-001.mp3",
"01-002.mp3"
]
},
"id": "d530ada48ea0b6f480c077af49f62bc6",
"status": "downloading"
}
18s later:
$ curl -X GET '/jobs/d530ada48ea0b6f480c077af49f62bc6'
{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73\u0026tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request\u0026X-Amz-Date=20230916T202904Z\u0026X-Amz-Expires=900\u0026X-Amz-Security-Token=dummy\u0026X-Amz-SignedHeaders=host\u0026x-id=PutObject\u0026X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52",
"variants": [
"01-001.mp3",
"01-002.mp3"
]
},
"id": "d530ada48ea0b6f480c077af49f62bc6",
"status": "processing"
}
54s later:
$ curl -X GET '/jobs/d530ada48ea0b6f480c077af49f62bc6'
{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73\u0026tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request\u0026X-Amz-Date=20230916T202904Z\u0026X-Amz-Expires=900\u0026X-Amz-Security-Token=dummy\u0026X-Amz-SignedHeaders=host\u0026x-id=PutObject\u0026X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52",
"variants": [
"01-001.mp3",
"01-002.mp3"
]
},
"id": "d530ada48ea0b6f480c077af49f62bc6",
"status": "uploading",
"result_media_duration": 2649000000000,
"result_file_bytes": 42580796
}
1s later:
$ curl -X GET '/jobs/d530ada48ea0b6f480c077af49f62bc6'
{
"url": "magnet:?xt=urn:btih:58C665647C1A34019A0DC99C9046BD459F006B73\u0026tr=http%3A%2F%2Fbt3.t-ru.org",
"type": "concatenate",
"params": {
"audioCodec": "mp3",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256\u0026X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request\u0026X-Amz-Date=20230916T202904Z\u0026X-Amz-Expires=900\u0026X-Amz-Security-Token=dummy\u0026X-Amz-SignedHeaders=host\u0026x-id=PutObject\u0026X-Amz-Signature=30496441c038a34d2ce84df5548de36424989a60bb7a8bdd50826bab8bcebf52",
"variants": [
"01-001.mp3",
"01-002.mp3"
]
},
"id": "d530ada48ea0b6f480c077af49f62bc6",
"status": "complete",
"result_media_duration": 2649000000000,
"result_file_bytes": 42580796
}
To download a YouTube video, you need to pass the URL of the video to the /jobs
endpoint.
$ curl -X POST '/jobs'--data-raw='{
"url": "https://www.youtube.com/watch?v=kPN-uWB28X8",
"type": "upload_original",
"params": {
"variant": "Audio (mp3), Low Quality",
"uploadUrl": "http://localhost:51169/some-bucket/some-path/some-file.some-ext?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=dummy%2F20230916%2F%2Fs3%2Faws4_request&X-Amz-Date=20230916T203019Z&X-Amz-Expires=900&X-Amz-Security-Token=dummy&X-Amz-SignedHeaders=host&x-id=PutObject&X-Amz-Signature=f1d37ccbe09a73b71f83dd60a6aa8ff2078847a01c146768c6092751f16f0952"
}
}'
{"status": "accepted", "id": "01666b866a2b1eabc3189160ba6a3afa"}