1 (изменено: shahlik002, 2018-07-10 13:33:37)

Тема: AHK: Instagram API

Доброго здоровья, форумчане!)
Подскажте, есть ли что-нибудь интересное с инстаграмом? Библиотеки??
На форуме ничего такого не нашел.
Можно конечно и интернет запросы использовать, но тогда понадобиться ваша помощь, ибо я в них не понимаю.
Хочется буржуйского функционала и все что б по полочкам было.

2

Re: AHK: Instagram API

А в гугле пробовали искать?

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

3

Re: AHK: Instagram API

shahlik002, смайлик точку не заменяет. Требую исправить!

4

Re: AHK: Instagram API

teadrinker
Да, пробовал.
На AHK дельного ничего не нашел, только через ie и не то что я хочу.
Нашел на питоне, тут красота.

5

Re: AHK: Instagram API

shahlik002 пишет:

На AHK дельного ничего не нашел, только через ie и не то что я хочу.

А что вы хотите?

6

Re: AHK: Instagram API

Malcev
Как можно больше функционала.
Как минимум возможность войти, поставить лайк, подписаться, искать посты, ждать постов от других аккаунтов.

Сайты для взаимной раскрутки так и хотят автоматизации.
Так же неплохо б было организовать директ для переписок с ПК.
Сейчас пользуюсь python-instagram API.
Можно как-то эту библиотеку перенести в AHK?

7

Re: AHK: Instagram API

shahlik002 пишет:

Можно как-то эту библиотеку перенести в AHK?

Можно. Переносите .

8

Re: AHK: Instagram API

А как перенесете не забудьте поделиться результатами.

9

Re: AHK: Instagram API

alexii
Malcev
А как это сделать?
Если бы я мог, я бы не создавал эту тему.

10 (изменено: DD, 2018-07-10 18:47:22)

Re: AHK: Instagram API

Да, каким будет напутствие Шахлику от наших опытных товарищей?)

11 (изменено: DD, 2018-07-10 18:51:08)

Re: AHK: Instagram API

Шахлик, а вам надо усвоить, как тут все работает:

12

Re: AHK: Instagram API

shahlik002, Смотреть код на питоне, что он посылает и повторить такое же в ахк.
А так-как, там отправляются http запросы, то я вижу 3 варианта:
1) Продолжать пользоваться питоновской библиотекой.
2) Понять как использовать веб-запрсы и перевести питон на ахк.
3) Обратиться за помощью в коммерческий раздел.

13

Re: AHK: Instagram API

Вот так логинится по этому недокументированному апи.
Токен даётся на 1 год.

username := "gmail@gmail.com"
password := "password"

API_URL := "https://i.instagram.com/api/v1/"
DEVICE_SETTINTS := {manufacturer: "Xiaomi", model: "HM 1SW", android_version: 18, android_release: 4.3}
USER_AGENT := "Instagram 10.26.0 Android (" DEVICE_SETTINTS["android_version"] "/" DEVICE_SETTINTS["android_release"] "; 320dpi; 720x1280; " DEVICE_SETTINTS["manufacturer"] "; " DEVICE_SETTINTS["model"] "; armani; qcom; en_US)"
IG_SIG_KEY := "4f8732eb9ba7d1c8e8897a75d6474d4eb3f5279137431b2aafb71fafe2abe178"
SIG_KEY_VERSION := 4

device_id := "android-" SubStr(bcrypt_md5(bcrypt_md5(username password) 12345), 1, 16)
uuid := generateUUID(true)
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")
HTTP.Open("GET", API_URL "si/fetch_headers/?challenge_type=signup&guid=" generateUUID(False), true)
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("Accept", "*/*")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.Send()
HTTP.WaitForResponse()
csrftoken := RegexReplace(HTTP.getAllResponseHeaders, "s)^.*Set-Cookie: csrftoken=(.+?);.*$", "$1")   ; даётся на год
data := "{""phone_id"": """ generateUUID(true) """, ""_csrftoken"": """ csrftoken """, ""username"": """ username """, ""guid"": """ uuid """, ""device_id"": """ device_id """, ""password"": """ password """, ""login_attempt_count"": ""0""}"
Signature := "ig_sig_key_version=" SIG_KEY_VERSION "&signed_body=" HMAC(IG_SIG_KEY, data, "SHA256") "." UriEncode(data)

HTTP.Open("POST", API_URL "accounts/login/", true)
HTTP.SetRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("Accept", "*/*")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.Send(Signature)
HTTP.WaitForResponse()
msgbox % HTTP.responsetext
return



generateUUID(type)
{
   VarSetCapacity(puuid, 16, 0)
   if !(DllCall("rpcrt4.dll\UuidCreate", "ptr", &puuid))
   {
      if !(DllCall("rpcrt4.dll\UuidToString", "ptr", &puuid, "uint*", suuid))
      {
         if type
            return StrGet(suuid), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
         else
            return StrReplace(StrGet(suuid), "-"), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
      }
   }
   return ""
}



UriEncode(Uri, RE="[0-9A-Za-z]")
{
   VarSetCapacity(Var, StrPut(Uri, "UTF-8"), 0), StrPut(Uri, &Var, "UTF-8")
   While Code := NumGet(Var, A_Index - 1, "UChar")
      Res .= (Chr:=Chr(Code)) ~= RE ? Chr : Format("%{:02X}", Code)
   Return, Res
}



bcrypt_md5(string)
{
    static BCRYPT_MD5_ALGORITHM := "MD5"
    static BCRYPT_OBJECT_LENGTH := "ObjectLength"
    static BCRYPT_HASH_LENGTH   := "HashDigestLength"

    if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
        throw Exception("Failed to load bcrypt.dll", -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_MD5_ALGORITHM, "ptr", 0, "uint", 0) != 0)
        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", cbHashObject, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    VarSetCapacity(pbHashObject, cbHashObject, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr", hAlgo, "ptr*", hHash, "ptr", &pbHashObject, "uint", cbHashObject, "ptr", 0, "uint", 0, "uint", 0) != 0)
        throw Exception("BCryptCreateHash: " NT_STATUS, -1)

    VarSetCapacity(pbInput, StrPut(string, "UTF-8"), 0) && cbInput := StrPut(string, &pbInput, "UTF-8") - 1
    if (NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", cbInput, "uint", 0) != 0)
        throw Exception("BCryptHashData: " NT_STATUS, -1)

    VarSetCapacity(pbHash, cbHash, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0) != 0)
        throw Exception("BCryptFinishHash: " NT_STATUS, -1)

    loop % cbHash
        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

    DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
    DllCall("FreeLibrary", "ptr", hBCRYPT)

    return hash
}




HMAC(Key, Message, Algo := "MD5")
{
   static Algorithms := {MD2:    {ID: 0x8001, Size:  64}
                                   , MD4:    {ID: 0x8002, Size:  64}
                                   , MD5:    {ID: 0x8003, Size:  64}
                                   , SHA:    {ID: 0x8004, Size:  64}
                                   , SHA256: {ID: 0x800C, Size:  64}
                                   , SHA384: {ID: 0x800D, Size: 128}
                                   , SHA512: {ID: 0x800E, Size: 128}}
   static iconst := 0x36
   static oconst := 0x5C
   if (!(Algorithms.HasKey(Algo)))
   {
      return ""
   }
   Hash := KeyHashLen := InnerHashLen := ""
   HashLen := 0
   AlgID := Algorithms[Algo].ID
   BlockSize := Algorithms[Algo].Size
   MsgLen := StrPut(Message, "UTF-8") - 1
   KeyLen := StrPut(Key, "UTF-8") - 1
   VarSetCapacity(K, KeyLen + 1, 0)
   StrPut(Key, &K, KeyLen, "UTF-8")
   if (KeyLen > BlockSize)
   {
      LC_CalcAddrHash(&K, KeyLen, AlgID, KeyHash, KeyHashLen)
   }

   VarSetCapacity(ipad, BlockSize + MsgLen, iconst)
   Addr := KeyLen > BlockSize ? &KeyHash : &K
   Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
   i := 0
   while (i < Length)
   {
      NumPut(NumGet(Addr + 0, i, "UChar") ^ iconst, ipad, i, "UChar")
      i++
   }
   if (MsgLen)
   {
      StrPut(Message, &ipad + BlockSize, MsgLen, "UTF-8")
   }
   LC_CalcAddrHash(&ipad, BlockSize + MsgLen, AlgID, InnerHash, InnerHashLen)

   VarSetCapacity(opad, BlockSize + InnerHashLen, oconst)
   Addr := KeyLen > BlockSize ? &KeyHash : &K
   Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
   i := 0
   while (i < Length)
   {
      NumPut(NumGet(Addr + 0, i, "UChar") ^ oconst, opad, i, "UChar")
      i++
   }
   Addr := &opad + BlockSize
   i := 0
   while (i < InnerHashLen)
   {
      NumPut(NumGet(InnerHash, i, "UChar"), Addr + i, 0, "UChar")
      i++
   }
   return LC_CalcAddrHash(&opad, BlockSize + InnerHashLen, AlgID)
}



LC_CalcAddrHash(addr, length, algid, byref hash = 0, byref hashlength = 0)
{
   static h := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f"]
   static b := h.minIndex()
   hProv := hHash := o := ""
   if (DllCall("advapi32\CryptAcquireContext", "Ptr*", hProv, "Ptr", 0, "Ptr", 0, "UInt", 24, "UInt", 0xf0000000))
   {
      if (DllCall("advapi32\CryptCreateHash", "Ptr", hProv, "UInt", algid, "UInt", 0, "UInt", 0, "Ptr*", hHash))
      {
         if (DllCall("advapi32\CryptHashData", "Ptr", hHash, "Ptr", addr, "UInt", length, "UInt", 0))
         {
            if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", 0, "UInt*", hashlength, "UInt", 0))
            {
               VarSetCapacity(hash, hashlength, 0)
               if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", &hash, "UInt*", hashlength, "UInt", 0))
               {
                  loop % hashlength
                  {
                     v := NumGet(hash, A_Index - 1, "UChar")
                     o .= h[(v >> 4) + b] h[(v & 0xf) + b]
                  }
               }
            }
         }
         DllCall("advapi32\CryptDestroyHash", "Ptr", hHash)
      }
      DllCall("advapi32\CryptReleaseContext", "Ptr", hProv, "UInt", 0)
   }
   return o
}
+ DD

14

Re: AHK: Instagram API

Malcev, в последнем коде — переменная csrftoken содержит токен? Спрашиваю, потому что там формат короче и он меняется после каждого запуска.

15

Re: AHK: Instagram API

Уже и не вспомню.
Но судя по коду для использования этого апи нам надо сгенерировать Signature, которая в свою очередь использует токен, который дается на год.
Так что, наверное, сгенерировав один раз Signature мы можем ее использовать целый год.

16

Re: AHK: Instagram API

Интересно, в чём разница, если скачивать через это апи с токеном — со скачиванием, как при переходах через браузер?

17

Re: AHK: Instagram API

Без понятия.
Никогда ни тем ни другим не пользовался.
Надо бы добавить загрузку фотографий для теста.

18 (изменено: DD, 2019-02-23 14:26:01)

Re: AHK: Instagram API

Знаю, что браузерные страницы тоже используют json, так что когда лимит запросов в час исчерпается — приходит сообщение «{"message": "rate limited", "status": "fail"}» и в браузере соответственно страницы не подгружаются. Так что, наверно, в любом случае лимитов не избежать.

19 (изменено: DD, 2019-02-23 14:29:37)

Re: AHK: Instagram API

Хотя, было бы интересно, за сколько запросов можно получить комментарии к посту? Может, там они все за минимум запросов выдаются, в отличие от имитации скачивания через браузер?

20 (изменено: Malcev, 2019-02-23 14:53:38)

Re: AHK: Instagram API

Похоже 20 комментариев за 1 запрос.
https://instagram-private-api.readthedo … media.html

+ DD

21 (изменено: DD, 2019-02-26 15:03:13)

Re: AHK: Instagram API

Вроде, маловато. Через браузер уже в первой партии — больше 50.

22 (изменено: Malcev, 2019-03-05 17:13:33)

Re: AHK: Instagram API

Решил проверить - после логина отправляем запрос:

mediaId := "448979387270691659_45818965"
n := 1   ; pagination
HTTP.Open("GET", API_URL "media/" mediaId "/comments/?max_id=" n, true)
HTTP.SetRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("Accept", "*/*")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.Send()
HTTP.WaitForResponse()
msgbox % clipboard := HTTP.ResponseText

Результат 20.
Также перенес функцию заливки фото:

username := "username"
password := "password"

API_URL := "https://i.instagram.com/api/v1/"
DEVICE_SETTINTS := {manufacturer: "Xiaomi", model: "HM 1SW", android_version: 18, android_release: 4.3}
USER_AGENT := "Instagram 10.26.0 Android (" DEVICE_SETTINTS["android_version"] "/" DEVICE_SETTINTS["android_release"] "; 320dpi; 720x1280; " DEVICE_SETTINTS["manufacturer"] "; " DEVICE_SETTINTS["model"] "; armani; qcom; en_US)"
IG_SIG_KEY := "4f8732eb9ba7d1c8e8897a75d6474d4eb3f5279137431b2aafb71fafe2abe178"
SIG_KEY_VERSION := 4

device_id := "android-" SubStr(bcrypt_md5(bcrypt_md5(username password) 12345), 1, 16)
uuid := generateUUID(true)
HTTP := ComObjCreate("WinHTTP.WinHTTPRequest.5.1")

; 1 time in 90 days
HTTP.Open("GET", API_URL "si/fetch_headers/?challenge_type=signup&guid=" generateUUID(False), true)
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("Accept", "*/*")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.Send()
HTTP.WaitForResponse()
csrftoken := RegexReplace(HTTP.getAllResponseHeaders, "s)^.*Set-Cookie: csrftoken=(.+?);.*$", "$1")   ; даётся на год
data := "{""phone_id"": """ generateUUID(true) """, ""_csrftoken"": """ csrftoken """, ""username"": """ username """, ""guid"": """ uuid """, ""device_id"": """ device_id """, ""password"": """ password """, ""login_attempt_count"": ""0""}"
Signature := "ig_sig_key_version=" SIG_KEY_VERSION "&signed_body=" HMAC(IG_SIG_KEY, data, "SHA256") "." UriEncode(data)

HTTP.Open("POST", API_URL "accounts/login/", true)
HTTP.SetRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("Accept", "*/*")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.Send(Signature)
HTTP.WaitForResponse()
username_id := RegexReplace(HTTP.getAllResponseHeaders, "s)^.*Set-Cookie: ds_user_id=(.+?);.*$", "$1")
token := RegexReplace(HTTP.getAllResponseHeaders, "s)^.*Set-Cookie: csrftoken=(.+?);.*$", "$1")
match := "", Pos := 1
While Pos := regexmatch(HTTP.getAllResponseHeaders, "s)Set-Cookie: (.+?)\R", match, pos+StrLen(match))
   cookie .= match1 "; "
msgbox % clipboard := "username_id := " username_id "`r`ntoken := """ token """`r`ncookie := """ StrReplace(cookie, """", """""") """"

photo := "C:\001.jpg"
caption := "test"
disable_comments := false

pToken := Gdip_StartUp()
pBitmap := Gdip_CreateBitmapFromFile(photo)
Gdip_GetImageDimensions(pBitmap, width, height)
Gdip_DisposeImage(pBitmap)
Gdip_ShutDown(pToken)
upload_id := A_NowUTC
EnvSub, upload_id, 1970, seconds
upload_id .= A_MSec
data := {photo: [photo], upload_id: upload_id,  _csrftoken: csrftoken, image_compression: "{""lib_name"":""jt"",""lib_version"":""1.3.0"",""quality"":""87""}"}

CreateFormData(PostData, hdr_ContentType, data)
HTTP.Open("POST", API_URL "upload/photo/", true)
HTTP.SetRequestHeader("Content-Type", hdr_ContentType)
HTTP.SetRequestHeader("X-IG-Capabilities", "3Q4=")
HTTP.SetRequestHeader("X-IG-Connection-Type", "WIFI")
HTTP.SetRequestHeader("Cookie2", "$Version=1")
HTTP.SetRequestHeader("Accept-Language", "en-US")
HTTP.SetRequestHeader("Accept-Encoding", "gzip, deflate")
HTTP.SetRequestHeader("Connection", "close")
HTTP.SetRequestHeader("User-Agent", USER_AGENT)
HTTP.SetRequestHeader("Cookie", cookie)
HTTP.Send(PostData)
HTTP.WaitForResponse()
if (HTTP.Status = 200)
{
   data := "{""_csrftoken"": """ token """, ""media_folder"": ""Instagram"", ""source_type"": 4, ""_uid"": " username_id ", ""_uuid"": """ uuid """, ""caption"": """ caption """, ""upload_id"": """ upload_id """, ""device"": {""manufacturer"": """ DEVICE_SETTINTS["manufacturer"] """, ""model"": """ DEVICE_SETTINTS["model"] """, ""android_version"": " DEVICE_SETTINTS["android_version"] ", ""android_release"": """ DEVICE_SETTINTS["android_release"] """}, ""edits"": {""crop_original_size"": [" width ".0 , " height ".0], ""crop_center"": [0.0, 0.0], ""crop_zoom"": 1.0}, ""extra"": {""source_width"": " width ", ""source_height"": " height "}}"
   if disable_comments
      data := SubStr(data, 1, -1) ", ""disable_comments"": 1}"
   Signature := "ig_sig_key_version=" SIG_KEY_VERSION "&signed_body=" HMAC(IG_SIG_KEY, data, "SHA256") "." UriEncode(data)
   HTTP.Open("POST", API_URL "media/configure/?", true)
   HTTP.SetRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")
   HTTP.SetRequestHeader("Connection", "close")
   HTTP.SetRequestHeader("Accept", "*/*")
   HTTP.SetRequestHeader("Cookie2", "$Version=1")
   HTTP.SetRequestHeader("Accept-Language", "en-US")
   HTTP.SetRequestHeader("User-Agent", USER_AGENT)
   HTTP.SetRequestHeader("Cookie", cookie)
   HTTP.Send(Signature)
   HTTP.WaitForResponse()
   if (HTTP.Status = 200)
   {
      data := "{""_uuid"": """ uuid """, ""_uid"": " username_id ", ""id"": " username_id ", ""_csrftoken"": """ token """, ""experiment"": ""ig_android_profile_contextual_feed""}"
      Signature := "ig_sig_key_version=" SIG_KEY_VERSION "&signed_body=" HMAC(IG_SIG_KEY, data, "SHA256") "." UriEncode(data)
      HTTP.Open("POST", API_URL "qe/expose/", true)
      HTTP.SetRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=UTF-8")
      HTTP.SetRequestHeader("Connection", "close")
      HTTP.SetRequestHeader("Accept", "*/*")
      HTTP.SetRequestHeader("Cookie2", "$Version=1")
      HTTP.SetRequestHeader("Accept-Language", "en-US")
      HTTP.SetRequestHeader("User-Agent", USER_AGENT)
      HTTP.SetRequestHeader("Cookie", cookie)
      HTTP.Send(Signature)
      HTTP.WaitForResponse()
      msgbox done
   }
   else
   {
      msgbox % HTTP.ResponseText
      return
   }
}
else
{
   msgbox % HTTP.ResponseText
   return
}






generateUUID(type)
{
   VarSetCapacity(puuid, 16, 0)
   if !(DllCall("rpcrt4.dll\UuidCreate", "ptr", &puuid))
   {
      if !(DllCall("rpcrt4.dll\UuidToString", "ptr", &puuid, "uint*", suuid))
      {
         if type
            return StrGet(suuid), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
         else
            return StrReplace(StrGet(suuid), "-"), DllCall("rpcrt4.dll\RpcStringFree", "uint*", suuid)
      }
   }
   return ""
}



UriEncode(Uri, RE="[0-9A-Za-z]")
{
   VarSetCapacity(Var, StrPut(Uri, "UTF-8"), 0), StrPut(Uri, &Var, "UTF-8")
   While Code := NumGet(Var, A_Index - 1, "UChar")
      Res .= (Chr:=Chr(Code)) ~= RE ? Chr : Format("%{:02X}", Code)
   Return, Res
}



bcrypt_md5(string)
{
    static BCRYPT_MD5_ALGORITHM := "MD5"
    static BCRYPT_OBJECT_LENGTH := "ObjectLength"
    static BCRYPT_HASH_LENGTH   := "HashDigestLength"

    if !(hBCRYPT := DllCall("LoadLibrary", "str", "bcrypt.dll", "ptr"))
        throw Exception("Failed to load bcrypt.dll", -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptOpenAlgorithmProvider", "ptr*", hAlgo, "ptr", &BCRYPT_MD5_ALGORITHM, "ptr", 0, "uint", 0) != 0)
        throw Exception("BCryptOpenAlgorithmProvider: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_OBJECT_LENGTH, "uint*", cbHashObject, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    if (NT_STATUS := DllCall("bcrypt\BCryptGetProperty", "ptr", hAlgo, "ptr", &BCRYPT_HASH_LENGTH, "uint*", cbHash, "uint", 4, "uint*", cbResult, "uint", 0) != 0)
        throw Exception("BCryptGetProperty: " NT_STATUS, -1)

    VarSetCapacity(pbHashObject, cbHashObject, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptCreateHash", "ptr", hAlgo, "ptr*", hHash, "ptr", &pbHashObject, "uint", cbHashObject, "ptr", 0, "uint", 0, "uint", 0) != 0)
        throw Exception("BCryptCreateHash: " NT_STATUS, -1)

    VarSetCapacity(pbInput, StrPut(string, "UTF-8"), 0) && cbInput := StrPut(string, &pbInput, "UTF-8") - 1
    if (NT_STATUS := DllCall("bcrypt\BCryptHashData", "ptr", hHash, "ptr", &pbInput, "uint", cbInput, "uint", 0) != 0)
        throw Exception("BCryptHashData: " NT_STATUS, -1)

    VarSetCapacity(pbHash, cbHash, 0)
    if (NT_STATUS := DllCall("bcrypt\BCryptFinishHash", "ptr", hHash, "ptr", &pbHash, "uint", cbHash, "uint", 0) != 0)
        throw Exception("BCryptFinishHash: " NT_STATUS, -1)

    loop % cbHash
        hash .= Format("{:02x}", NumGet(pbHash, A_Index - 1, "uchar"))

    DllCall("bcrypt\BCryptDestroyHash", "ptr", hHash)
    DllCall("bcrypt\BCryptCloseAlgorithmProvider", "ptr", hAlgo, "uint", 0)
    DllCall("FreeLibrary", "ptr", hBCRYPT)

    return hash
}




HMAC(Key, Message, Algo := "MD5")
{
   static Algorithms := {MD2:    {ID: 0x8001, Size:  64}
                                   , MD4:    {ID: 0x8002, Size:  64}
                                   , MD5:    {ID: 0x8003, Size:  64}
                                   , SHA:    {ID: 0x8004, Size:  64}
                                   , SHA256: {ID: 0x800C, Size:  64}
                                   , SHA384: {ID: 0x800D, Size: 128}
                                   , SHA512: {ID: 0x800E, Size: 128}}
   static iconst := 0x36
   static oconst := 0x5C
   if (!(Algorithms.HasKey(Algo)))
   {
      return ""
   }
   Hash := KeyHashLen := InnerHashLen := ""
   HashLen := 0
   AlgID := Algorithms[Algo].ID
   BlockSize := Algorithms[Algo].Size
   MsgLen := StrPut(Message, "UTF-8") - 1
   KeyLen := StrPut(Key, "UTF-8") - 1
   VarSetCapacity(K, KeyLen + 1, 0)
   StrPut(Key, &K, KeyLen, "UTF-8")
   if (KeyLen > BlockSize)
   {
      LC_CalcAddrHash(&K, KeyLen, AlgID, KeyHash, KeyHashLen)
   }

   VarSetCapacity(ipad, BlockSize + MsgLen, iconst)
   Addr := KeyLen > BlockSize ? &KeyHash : &K
   Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
   i := 0
   while (i < Length)
   {
      NumPut(NumGet(Addr + 0, i, "UChar") ^ iconst, ipad, i, "UChar")
      i++
   }
   if (MsgLen)
   {
      StrPut(Message, &ipad + BlockSize, MsgLen, "UTF-8")
   }
   LC_CalcAddrHash(&ipad, BlockSize + MsgLen, AlgID, InnerHash, InnerHashLen)

   VarSetCapacity(opad, BlockSize + InnerHashLen, oconst)
   Addr := KeyLen > BlockSize ? &KeyHash : &K
   Length := KeyLen > BlockSize ? KeyHashLen : KeyLen
   i := 0
   while (i < Length)
   {
      NumPut(NumGet(Addr + 0, i, "UChar") ^ oconst, opad, i, "UChar")
      i++
   }
   Addr := &opad + BlockSize
   i := 0
   while (i < InnerHashLen)
   {
      NumPut(NumGet(InnerHash, i, "UChar"), Addr + i, 0, "UChar")
      i++
   }
   return LC_CalcAddrHash(&opad, BlockSize + InnerHashLen, AlgID)
}



LC_CalcAddrHash(addr, length, algid, byref hash = 0, byref hashlength = 0)
{
   static h := [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "a", "b", "c", "d", "e", "f"]
   static b := h.minIndex()
   hProv := hHash := o := ""
   if (DllCall("advapi32\CryptAcquireContext", "Ptr*", hProv, "Ptr", 0, "Ptr", 0, "UInt", 24, "UInt", 0xf0000000))
   {
      if (DllCall("advapi32\CryptCreateHash", "Ptr", hProv, "UInt", algid, "UInt", 0, "UInt", 0, "Ptr*", hHash))
      {
         if (DllCall("advapi32\CryptHashData", "Ptr", hHash, "Ptr", addr, "UInt", length, "UInt", 0))
         {
            if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", 0, "UInt*", hashlength, "UInt", 0))
            {
               VarSetCapacity(hash, hashlength, 0)
               if (DllCall("advapi32\CryptGetHashParam", "Ptr", hHash, "UInt", 2, "Ptr", &hash, "UInt*", hashlength, "UInt", 0))
               {
                  loop % hashlength
                  {
                     v := NumGet(hash, A_Index - 1, "UChar")
                     o .= h[(v >> 4) + b] h[(v & 0xf) + b]
                  }
               }
            }
         }
         DllCall("advapi32\CryptDestroyHash", "Ptr", hHash)
      }
      DllCall("advapi32\CryptReleaseContext", "Ptr", hProv, "UInt", 0)
   }
   return o
}



Gdip_Startup()
{
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   if !DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
      DllCall("LoadLibrary", "str", "gdiplus")
   VarSetCapacity(si, A_PtrSize = 8 ? 24 : 16, 0), si := Chr(1)
   DllCall("gdiplus\GdiplusStartup", A_PtrSize ? "UPtr*" : "uint*", pToken, Ptr, &si, Ptr, 0)
   return pToken
}

Gdip_Shutdown(pToken)
{
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   DllCall("gdiplus\GdiplusShutdown", Ptr, pToken)
   if hModule := DllCall("GetModuleHandle", "str", "gdiplus", Ptr)
      DllCall("FreeLibrary", Ptr, hModule)
   return 0
}

Gdip_CreateBitmapFromFile(sFile, IconNumber=1, IconSize="")
{
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   , PtrA := A_PtrSize ? "UPtr*" : "UInt*"
   if (!A_IsUnicode)
   {
      VarSetCapacity(wFile, 1024)
      DllCall("kernel32\MultiByteToWideChar", "uint", 0, "uint", 0, Ptr, &sFile, "int", -1, Ptr, &wFile, "int", 512)
      DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &wFile, PtrA, pBitmap)
   }
   else
      DllCall("gdiplus\GdipCreateBitmapFromFile", Ptr, &sFile, PtrA, pBitmap)
   return pBitmap
}

Gdip_GetImageDimensions(pBitmap, ByRef Width, ByRef Height)
{
   Ptr := A_PtrSize ? "UPtr" : "UInt"
   DllCall("gdiplus\GdipGetImageWidth", Ptr, pBitmap, "uint*", Width)
   DllCall("gdiplus\GdipGetImageHeight", Ptr, pBitmap, "uint*", Height)
}

Gdip_DisposeImage(pBitmap)
{
   return DllCall("gdiplus\GdipDisposeImage", A_PtrSize ? "UPtr" : "UInt", pBitmap)
}



; CreateFormData() by tmplinshi, AHK Topic: https://autohotkey.com/boards/viewtopic.php?t=7647
; Thanks to Coco: https://autohotkey.com/boards/viewtopic.php?p=41731#p41731
; Modified version by SKAN, 09/May/2016

CreateFormData(ByRef retData, ByRef retHeader, objParam) {
	New CreateFormData(retData, retHeader, objParam)
}

Class CreateFormData {

	__New(ByRef retData, ByRef retHeader, objParam) {

		Local CRLF := "`r`n", i, k, v, str, pvData
		; Create a random Boundary
		Local Boundary := this.RandomBoundary()
		Local BoundaryLine := "------------------------------" . Boundary

    this.Len := 0 ; GMEM_ZEROINIT|GMEM_FIXED = 0x40
    this.Ptr := DllCall( "GlobalAlloc", "UInt",0x40, "UInt",1, "Ptr"  )          ; allocate global memory

		; Loop input paramters
		For k, v in objParam
		{
			If IsObject(v) {
				For i, FileName in v
				{
					str := BoundaryLine . CRLF
					     . "Content-Disposition: form-data; name=""" . k . """; filename=""" . FileName . """" . CRLF
					     . "Content-Type: " . this.MimeType(FileName) . CRLF . CRLF
          this.StrPutUTF8( str )
          this.LoadFromFile( Filename )
          this.StrPutUTF8( CRLF )
				}
			} Else {
				str := BoundaryLine . CRLF
				     . "Content-Disposition: form-data; name=""" . k """" . CRLF . CRLF
				     . v . CRLF
        this.StrPutUTF8( str )
			}
		}

		this.StrPutUTF8( BoundaryLine . "--" . CRLF )

    ; Create a bytearray and copy data in to it.
    retData := ComObjArray( 0x11, this.Len ) ; Create SAFEARRAY = VT_ARRAY|VT_UI1
    pvData  := NumGet( ComObjValue( retData ) + 8 + A_PtrSize )
    DllCall( "RtlMoveMemory", "Ptr",pvData, "Ptr",this.Ptr, "Ptr",this.Len )

    this.Ptr := DllCall( "GlobalFree", "Ptr",this.Ptr, "Ptr" )                   ; free global memory 

    retHeader := "multipart/form-data; boundary=----------------------------" . Boundary
	}

  StrPutUTF8( str ) {
    Local ReqSz := StrPut( str, "utf-8" ) - 1
    this.Len += ReqSz                                  ; GMEM_ZEROINIT|GMEM_MOVEABLE = 0x42
    this.Ptr := DllCall( "GlobalReAlloc", "Ptr",this.Ptr, "UInt",this.len + 1, "UInt", 0x42 )   
    StrPut( str, this.Ptr + this.len - ReqSz, ReqSz, "utf-8" )
  }
  
  LoadFromFile( Filename ) {
    Local objFile := FileOpen( FileName, "r" )
    this.Len += objFile.Length                     ; GMEM_ZEROINIT|GMEM_MOVEABLE = 0x42 
    this.Ptr := DllCall( "GlobalReAlloc", "Ptr",this.Ptr, "UInt",this.len, "UInt", 0x42 )
    objFile.RawRead( this.Ptr + this.Len - objFile.length, objFile.length )
    objFile.Close()       
  }

	RandomBoundary() {
		str := "0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z"
		Sort, str, D| Random
		str := StrReplace(str, "|")
		Return SubStr(str, 1, 12)
	}

	MimeType(FileName) {
		n := FileOpen(FileName, "r").ReadUInt()
		Return (n        = 0x474E5089) ? "image/png"
		     : (n        = 0x38464947) ? "image/gif"
		     : (n&0xFFFF = 0x4D42    ) ? "image/bmp"
		     : (n&0xFFFF = 0xD8FF    ) ? "image/jpeg"
		     : (n&0xFFFF = 0x4949    ) ? "image/tiff"
		     : (n&0xFFFF = 0x4D4D    ) ? "image/tiff"
		     : "application/octet-stream"
	}

}

После успешного логина нужно сохранить кукисы, token и username_id.
И в дальнейшем эти кукисы отправлять в запросах, чтобы каждый раз не логиниться.
Так как за постоянный логин может последовать бан.
Кукисы действительны в течении 90 дней.