Created
June 21, 2020 04:00
-
-
Save Daniel-Worrall/dfd4de93cb117beea8a49609ba3c98d9 to your computer and use it in GitHub Desktop.
twist.moe Downloader Crystal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "./twist" | |
CHUNK_SIZE = 1024 | |
name = "" | |
path = "" | |
Dir.mkdir_p(path) | |
Twist.get_sources(name).each do |source| | |
filename = "#{path}/#{name} E#{source.number.to_s.rjust(2, '0')}.mp4" | |
print filename | |
response = HTTP::Client.head("https://twist.moe#{source.link}") | |
while response.status_code == 302 | |
response = HTTP::Client.get(response.headers.get("Location").first, headers: HTTP::Headers{"Referer" => "https://twist.moe/"}) do |r| | |
next r if r.status_code == 302 | |
puts " - #{r.headers.get("Content-Length").first.to_i.humanize}B" | |
io = r.body_io | |
chunk = Slice(UInt8).new(CHUNK_SIZE) | |
File.open(filename, "w") do |file| | |
while (count = io.read(chunk)) > 0 | |
if count == CHUNK_SIZE | |
file.write(chunk) | |
else | |
file.write chunk[0...count] | |
end | |
end | |
end | |
r | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "http/client" | |
require "json" | |
require "openssl" | |
module Twist | |
TOKEN = "1rj2vRtegS8Y60B3w3qNZm5T2Q0TN2NR" | |
KEY = "LXgIVP&PorO68Rq7dTx8N^lP!Fa5sGJ^*XK" | |
alias Sources = Array(Source) | |
struct Anime | |
include JSON::Serializable | |
property id : Int32 | |
property title : String | |
property alt_title : Nil | |
property season : Int32 | |
property ongoing : Int32 | |
property description : String | |
property hb_id : Int32 | |
property created_at : String | |
property updated_at : String | |
property hidden : Int32 | |
property mal_id : Nil | |
property slug : Source | |
property episodes : Array(Source) | |
end | |
struct Source | |
include JSON::Serializable | |
property id : Int32 | |
property source : String? | |
property number : Int32? | |
property anime_id : Int32 | |
property created_at : String | |
property updated_at : String | |
property slug : String? | |
def link | |
raise "No source" unless source | |
cipher = OpenSSL::Cipher.new("aes-256-cbc") | |
encrypted = Base64.decode_string(source.not_nil!) | |
salt = encrypted.to_slice[8, 8] | |
my_data = KEY + String.new(salt) | |
final_key = key = String.build { |str| str.write(OpenSSL::MD5.hash(my_data).to_slice) } | |
while final_key.to_slice.size < 48 | |
key = String.build { |str| str.write(OpenSSL::MD5.hash(key + my_data).to_slice) } | |
final_key += key | |
end | |
cipher.key = String.new(final_key.to_slice[0...32]) | |
cipher.iv = String.new(final_key.to_slice[32...48]) | |
cipher.decrypt | |
String.build do |str| | |
str.write(cipher.update(encrypted.to_slice[16..])) | |
str.write(cipher.final) | |
end | |
end | |
end | |
def self.get_anime(anime) : Anime | |
Anime.from_json(HTTP::Client.get("https://twist.moe/api/anime/#{anime}", headers: HTTP::Headers{"x-access-token" => TOKEN}).body) | |
end | |
def self.get_sources(anime) : Sources | |
Sources.from_json(HTTP::Client.get("https://twist.moe/api/anime/#{anime}/sources", headers: HTTP::Headers{"x-access-token" => TOKEN}).body) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment