1 (изменено: kolotilov256, 2020-03-03 17:06:29)

Тема: AHK: Загрузка фотографии в беседу через API ВКонтакте

Здравствуйте.
Подскажите пожалуйста, почему в беседу ВКонтакте (созданную через группу) не получается отправить фотографию?

Выдаёт вот такую ошибку:
https://imgur.com/9GNJmSl.png

P.S: Да, я понимаю, что скорее всего дело в отрицательном user_id (т.к это беседа, а не определённый человек), но что писать вместо него? В документации API ВКонтакте покопался, в методах photos.getMessagesUploadServer , photos.saveMessagesPhoto , и там к сожалению нет никаких намёков об отправке в беседу.

Code:

+ открыть спойлер
#SingleInstance Force
#Persistent
#NoEnv
#Include CreateFormData.ahk

global vk_id := 123456789
global vk_token := "b8da9ffae451f1453e3beded6afae451f1453b82d759f60473fae451f1453cfe95dfae451f1453bc83ec519f"
global conversation := 1

global chat_id := 2000000000 + conversation
global proxy := "https://" ; "https://vk-api-proxy.xtrafrancyz.net/_/"

uploadScreenshotToVK("screen.png")
ExitApp

JsonEvalToObj(json_text)
{
   JSONvar = 
   (LTrim Join 
   %json_text% 
   )

   htmldoc := ComObjCreate("htmlfile") 
   Script := htmldoc.Script 
   Script.execScript(" ", "JScript") 
   json_obj := Script.eval("(" . JSONvar . ")") 
   
   return json_obj
}

uploadScreenshotToVK(file_path)
{
   HTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
   if conversation
      HTTP.Open("GET", proxy "api.vk.com/method/photos.getMessagesUploadServer?&access_token=" vk_token "&v=5.103", true)
   else HTTP.Open("GET", proxy "api.vk.com/method/photos.getMessagesUploadServer?peer_id=" vk_id "&access_token=" vk_token "&v=5.103", true)
   HTTP.Send()
   HTTP.WaitForResponse()
   RegexMatch(HTTP.responsetext, "upload_url"":""(.+?)""", match)
   server := StrReplace(match1, "\/", "/")
   objParam := {photo: [file_path]}
   
   CreateFormData(PostData, hdr_ContentType, objParam)
   HTTP.Open("POST", server, true)
   HTTP.SetRequestHeader("Content-Type", hdr_ContentType)
   HTTP.Send(PostData)
   HTTP.WaitForResponse()
   RegexMatch(HTTP.responsetext, "\{""server"":(.+?),""photo"":""(.+?)"",""hash"":""(.+?)""", match)
   match2 := StrReplace(match2, "\""", """")

   HTTP.Open("GET", proxy "api.vk.com/method/photos.saveMessagesPhoto?server=" match1 "&photo=" match2 "&hash=" match3 "&access_token=" vk_token "&v=5.103", true)
   HTTP.Send()
   HTTP.WaitForResponse()

   json_obj := JsonEvalToObj(HTTP.ResponseText)
   attachment := "photo" json_obj.response.0.owner_id "_" json_obj.response.0.id
   
   HTTP := ComObjCreate("WinHttp.WinHttpRequest.5.1")
   if conversation
      HTTP.Open("GET", proxy "api.vk.com/method/messages.send?v=5.85&access_token=" vk_token "&user_id=" conversation "&message=&attachment=" attachment, false)
   else HTTP.Open("GET", proxy "api.vk.com/method/messages.send?v=5.85&access_token=" vk_token "&user_id=" vk_id "&message=&attachment=" attachment, false)
   HTTP.Send()
   HTTP.WaitForResponse()
   
   msgBox % HTTP.ResponseText
}

Include code:

+ открыть спойлер

; 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"
	}

}

2

Re: AHK: Загрузка фотографии в беседу через API ВКонтакте

А где в апи написано, что если peer_id - группа, то ее айди указывать не надо?

  if conversation
      HTTP.Open("GET", proxy "api.vk.com/method/photos.getMessagesUploadServer?&access_token=" vk_token "&v=5.103", true)
   else HTTP.Open("GET", proxy "api.vk.com/method/photos.getMessagesUploadServer?peer_id=" vk_id "&access_token=" vk_token "&v=5.103", true)

3 (изменено: kolotilov256, 2020-03-03 17:25:16)

Re: AHK: Загрузка фотографии в беседу через API ВКонтакте

Вот только вопрос, что указывать в peer_id ?
Пробовал id самой группы (https://vk.com/club182104136) (Вот эти 182104136)
Пробовал chat_id (который 200000000+cвой ид)
Пробовал отрицательный id (-182104136)

Ничего не сработало.

А по поводу того, почему удалил peer_id :
По моей логике фотография должна загружается куда-то в саму группу, а далее уже передаваться прикреплённой ссылкой в беседу.
На скриншоте в документации так и написано (Параметр peer_id , для загрузки фотографии в сообщениях сообществ)
У меня не личные сообщения сообщества, у меня беседа сообщества.

https://imgur.com/lpRc8Uv.png

4

Re: AHK: Загрузка фотографии в беседу через API ВКонтакте

peer_id - это получатель.
Надо тут читать:
https://vk.com/dev/bots_docs

5

Re: AHK: Загрузка фотографии в беседу через API ВКонтакте

Потанцевал танцы с бубнами с документацией, и до меня допёрло.
Всё таки написано там про это, не досмотрел.

https://imgur.com/l03YuON.png

Вот так в моём коде надо запросы отредактировать и всё пашет

HTTP.Open("GET", proxy "api.vk.com/method/photos.getMessagesUploadServer?peer_id=" vk_id "&&access_token=" vk_token "&v=5.103", true)

HTTP.Open("GET", proxy "api.vk.com/method/messages.send?v=5.85&access_token=" vk_token "&chat_id=" conversation "&peer_id=" chat_id "&message=&attachment=" attachment, false)