API Usages
Shotit API provides a HTTP interface for developers to interact with Shotit
programmatically.
Using the API, you can develop programs such as: chat bots, browser plugins, video tagging / deduplication applications, games or whatever scripts that you need to know the video info from a screenshot.
Please replace api.yourendpoints.domain
with your own shotit api service domain.
/search
Search by image URL
- cURL
- JavaScript
- Python
- PowerShell
curl "https://api.yourendpoints.domain/search?url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
await fetch(
`https://api.yourendpoints.domain/search?url=${encodeURIComponent(
'https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png'
)}`
).then((e) => e.json());
import requests
import urllib.parse
requests
.get("https://api.yourendpoints.domain/search?url={}"
.format(urllib.parse.quote_plus("https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"))
).json()
Invoke-RestMethod "https://api.yourendpoints.domain/search?url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
This method is the easiest if your image is already hosted somewhere in public. Otherwise, you must upload the image.
Search by image upload
- cURL
- JavaScript
- Python
- PowerShell
curl --data-binary "@demo.jpg" https://api.yourendpoints.domain/search
// For nodejs only
import fs from 'fs';
import fetch from 'node-fetch';
await fetch('https://api.yourendpoints.domain/search', {
method: 'POST',
body: fs.readFileSync('demo.jpg'),
headers: { 'Content-type': 'image/jpeg' },
}).then((e) => e.json());
import requests
requests.post("https://api.yourendpoints.domain/search",
data=open("demo.jpg", "rb"),
headers={"Content-Type": "image/jpeg"}
).json()
Invoke-RestMethod -Method Post -InFile .\demo.jpg https://api.yourendpoints.domain/search
Supported Content-Types are image/*
, video/*
, application/octet-stream
and application/x-www-form-urlencoded
File size is limited to 25MB. The server would throw HTTP 413 Payload Too Large if it is too large.
Search by FORM POST (multipart/form-data)
- HTML
- cURL
- JavaScript
- Python
- PowerShell
<form
action="https://api.yourendpoints.domain/search"
method="POST"
enctype="multipart/form-data"
>
<input type="file" name="image" />
<input type="submit" />
</form>
curl -F "image=@demo.jpg" https://api.yourendpoints.domain/search
// For web browsers only
const formData = new FormData();
formData.append('image', imageBlob);
await fetch('https://api.yourendpoints.domain/search', {
method: 'POST',
body: formData,
}).then((e) => e.json());
import requests
requests.post("https://api.yourendpoints.domain/search",
files={"image": open("demo.jpg", "rb")}
).json()
// Requires PowerShell 7.x
Invoke-RestMethod -Method Post -Form @{image=Get-Item -Path "demo.jpg"} https://api.yourendpoints.domain/search
File size is limited to 25MB. The server would throw HTTP 413 Payload Too Large if it is too large.
Cut Black Borders
shotit can detect black borders automatically and cut away unnecessary parts of the images that would affect search results accuracy. This is useful if your image is a screencap from a smartphone or iPad that contains black bars.
To enable black border crop, add cutBorders
to the query string. e.g.
- cURL
- JavaScript
- Python
- PowerShell
curl "https://api.yourendpoints.domain/search?cutBorders&url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
await fetch(
`https://api.yourendpoints.domain/search?cutBorders&url=${encodeURIComponent(
'https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png'
)}`
).then((e) => e.json());
import requests
import urllib.parse
requests
.get("https://api.yourendpoints.domain/search?cutBorders&url={}"
.format(urllib.parse.quote_plus("https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"))
).json()
Invoke-RestMethod "https://api.yourendpoints.domain/search?cutBorders&url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
Filter by imdb ID
You can search for a matching scene only in a particular anime by imdb ID. This is useful when you are certain about the anime name but cannot remember which episode.
First you have to look for the imdb ID of your anime from imdb first. Then add imdbID=1
to the query string. e.g. imdb ID of Cowboy Bebop is 1
- cURL
- JavaScript
- Python
- PowerShell
curl "https://api.yourendpoints.domain/search?imdbID=1&url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
await fetch(
`https://api.yourendpoints.domain/search?imdbID=1&url=${encodeURIComponent(
'https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png'
)}`
).then((e) => e.json());
import requests
import urllib.parse
requests
.get("https://api.yourendpoints.domain/search?imdbID=1&url={}"
.format(urllib.parse.quote_plus("https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"))
).json()
Invoke-RestMethod "https://api.yourendpoints.domain/search?imdbID=1&url=https://i.ibb.co/KGwVkqy/big-buck-bunny-10.png"
Search Image Format
shotit support any media format that can be decoded by ffmpeg, including video and gif. When using video / gif, only the 1st frame would be extracted for searching.
Your image / video must be smaller than 25MB. Otherwise it would fail with HTTP 413 (Request Entity Too Large).
The recommended resolution is 640 x 360px, higher resolution doesn't yield better search results. The algorithm is also resistant to jpeg artifacts, so you don't have to use uncompressed formats like png.
Response format
{
"frameCount": 745506,
"error": "",
"result": [
{
"imdb": 99939,
"filename": "Nekopara - OVA (BD 1280x720 x264 AAC).mp4",
"episode": null,
"from": 97.75,
"to": 98.92,
"similarity": 0.9440424588727485,
"video": "https://media.shotit/video/99939/Nekopara%20-%20OVA%20(BD%201280x720%20x264%20AAC).mp4?t=98.335&now=1653892514&token=xxxxxxxxxxxxxx",
"image": "https://media.shotit/image/99939/Nekopara%20-%20OVA%20(BD%201280x720%20x264%20AAC).mp4.jpg?t=98.335&now=1653892514&token=xxxxxxxxxxxxxx"
}
]
}
Fields | Meaning | Value |
---|---|---|
frameCount | Total number of frames searched | number |
error | Error message | string |
result | Search results (see table below) | Array of Objects |
Fields | Meaning | Value |
---|---|---|
imdb | The matching imdb ID or imdb info | number or object |
filename | The filename of file where the match is found | string |
episode | The extracted episode number from filename | Refer to aniep |
from | Starting time of the matching scene (seconds) | number |
to | Ending time of the matching scene (seconds) | number |
similarity | Similarity compared to the search image | number (0 to 1) |
video | URL to the preview video of the matching scene | string |
image | URL to the preview image of the matching scene | string |
- Results are sorted from most similar to least similar
- Similarity lower than 90% are most likely incorrect results. It's up to you to judge what is a match and what is just visually similar.
episode
can be null because it is just a result of parsing thefilename
with aniep
By default, it only returns imdb ID for search results. To get more anime info, make a second query to imdb API. If you need chinese-translated titles, take a look at imdb-chinese
Error codes
Example Error response
{
"error": "Concurrency limit exceeded"
}
HTTP Status | Possible Causes |
---|---|
400 | Invalid image url / Failed to process image / OpenCV: Failed to detect and cut borders |
402 | Search quota depleted / Concurrency limit exceeded |
403 | Invalid API key |
405 | Method Not Allowed |
500 | Internal Server Error |
503 | Search queue is full / Database is not responding |
504 | Server is overloaded |
the "error" value is empty string when there's no error
Media Preview
The url you obtained from image
and video
from search result is served by shotit-media
These urls would expire in 300 seconds (5 minutes)
It can generate image or video preview of 3 sizes by appending size=l
(large), size=m
(medium, default) or size=s
(small) at the end of the url. e.g.
https://media.shotit/image/xxx/xxxxxx.mp4.jpg?t=0&now=1653892514&token=xxxxx&size=s
https://media.shotit/video/xxx/xxxxxx.mp4?t=0&now=1653892514&token=xxxxx&size=s
For video preview, it can generate a video with sound (default), or a muted video by appending mute
to the end of url. e.g.
https://media.shotit/video/xxx/xxxxxx.mp4?t=0&now=1653892514&token=xxxxx&mute
https://media.shotit/video/xxx/xxxxxx.mp4?t=0&now=1653892514&token=xxxxx&size=s&mute
The media server would detect boundaries of the scene and cut videos at the boundaries. You cannot specify the length of video preview.
Do not attempt to parse and modify the urls except documented above. The urls are not permanent and may change without notice.
Error codes
HTTP Status | Meaning |
---|---|
200 | OK |
400 | Invalid url param |
403 | Invalid token |
404 | File not found |
410 | Token Expired |
>=500 | Server Error (Maybe broken video or overloaded) |
/me
Let you check the search quota and limit for your account (with API key) or IP address (without API key).
- cURL
- JavaScript
- Python
- PowerShell
curl "https://api.yourendpoints.domain/me"
await fetch('https://api.yourendpoints.domain/me').then((e) => e.json());
import requests
requests.get("https://api.yourendpoints.domain/me").json()
Invoke-RestMethod "https://api.yourendpoints.domain/me"
Example Response
{
"id": "127.0.0.1",
"priority": 0,
"concurrency": 1,
"quota": 1000,
"quotaUsed": 43
}
Fields | Meaning | Value |
---|---|---|
id | IP address (guest) or email address (user) | string |
priority | Your priority in search queue | number (0: lowest) |
concurrency | Number of parallel search requests you can make | number |
quota | Search quota you have for this month | number |
quotaUsed | Search quota you have used this month | number |
Using the API with API Keys
If you have an API Key that grants you more search quota and limits, put your API key in either HTTP header x-trace-key
or query string key
.
When searching with API Keys, it would count towards your account quota and limits. When searching without an API Key, you search as guests using your IP address.
Using API Keys in HTTP header
- cURL
- JavaScript
- Python
- PowerShell
curl -H "x-trace-key: xxxxxxxxxxxxxxxxxxxxxxx" "https://api.yourendpoints.domain/me"
await fetch('https://api.yourendpoints.domain/me', {
headers: {
'x-trace-key': 'xxxxxxxxxxxxxxxxxxxxxxx',
},
}).then((e) => e.json());
import requests
requests.get("https://api.yourendpoints.domain/me", headers={
"x-trace-key": "xxxxxxxxxxxxxxxxxxxxxxx"
}).json()
Invoke-RestMethod -Headers @{"x-trace-key" = "xxxxxxxxxxxxxxxxxxxxxxx"} https://api.yourendpoints.domain/me
Using API Keys in query string
If you're lazy and don't mind your API Key being exposed to browser history or logs. Just put your key in key in query string
- cURL
- JavaScript
- Python
- PowerShell
curl "https://api.yourendpoints.domain/me?key=xxxxxxxxxxxxxxxxxxxxxxx"
await fetch(
'https://api.yourendpoints.domain/me?key=xxxxxxxxxxxxxxxxxxxxxxx'
).then((e) => e.json());
import requests
requests.get("https://api.yourendpoints.domain/me?key=xxxxxxxxxxxxxxxxxxxxxxx").json()
Invoke-RestMethod "https://api.yourendpoints.domain/me?key=xxxxxxxxxxxxxxxxxxxxxxx"