<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[Серый форум &mdash; AHK: v2 loop files на яндекс-диске]]></title>
		<link>https://forum.script-coding.com/viewtopic.php?id=18469</link>
		<atom:link href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=18469&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «AHK: v2 loop files на яндекс-диске».]]></description>
		<lastBuildDate>Mon, 08 Sep 2025 07:59:33 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162693#p162693</link>
			<description><![CDATA[<p>Быстрый вариант с датами<br /></p><div class="codebox"><pre><code>; для создания каталога своего яндекс-диска из плоского списка
; с датами по самому раннему файлу в папке, без пустых папок
; токен должен быть в файле YandexToken.txt, рядом со скриптом

#Requires AutoHotkey v2
#DllLoad &#039;WinHttp.dll&#039;
#Include &lt;LightJson&gt;	; https://forum.script-coding.com/viewtopic.php?id=18483
#Include &lt;WebRequest&gt;	; https://forum.script-coding.com/viewtopic.php?pid=162651#p162651
#Include &lt;UrlCodec&gt;		; https://forum.script-coding.com/viewtopic.php?pid=162669#p162669

; сортировка вставками из Википедии
InsSortAMap(A, item := &#039;&#039;, lo := 1, hi?) {
	if !IsSet(hi)
		hi := A.Length
	j := lo + 1
	while j &lt;= hi {
		Aj := A[j]
		pivot:= item ? Aj[item] : Aj
		i := j - 1
		while i &gt;= lo &amp;&amp; StrCompare(item ? A[i][item] : A[i], pivot, &#039;On&#039;) &gt; 0
			A[i + 1] := A[i--]
		A[i+1] := Aj
		j++
	}
}

; сортировка по схеме Хоара из Википедии, модифицированная
qSortAMap(A, item := &#039;&#039;, lo := 1, hi?, threshold := 15, depth := 0) {

	static partition(A, item, low, high) {
		pivot:= item ? A[(low + high) &gt;&gt; 1][item] : A[(low + high) &gt;&gt; 1]
		i := low
		j := high
		loop {
			while StrCompare(item ? A[i][item] : A[i], pivot, &#039;On&#039;) &lt; 0
              i++
			while StrCompare(item ? A[j][item] : A[j], pivot, &#039;On&#039;) &gt; 0
              j--
			if i &gt;= j
				return j
			; swap
			temp := A[i], A[i] := A[j], A[j] := temp
			i++, j--
		}
	}

	if !IsSet(hi)
		hi := A.Length
	while hi - lo &gt; threshold {
		p:= partition(A, item, lo, hi)
		if p - lo &lt; hi - p {
			qSortAMap(A, item, lo, p, threshold, 1)
			lo := p + 1
		} else {
			qSortAMap(A, item, p + 1, hi, threshold, 1)
			hi := p
		}
	}

	if !depth
		InsSortAMap A, item

}

; найти в отсортированном массиве 1-ю строку с указанным началом
SASearch(A, &amp;str, item := &#039;&#039;) {
	if !j := A.Length
		return 0
	i := 1, L := StrLen(str)
	loop {
		m := i + ((j - i) &gt;&gt; 1)
		if StrCompare(str, substr(item ? A[m][item] : A[m], 1, L), &#039;On&#039;) &lt;= 0
			j := m - 1
		else i := m + 1
	} until i &gt; j
	return  ++j &lt;= A.Length &amp;&amp; StrCompare(str, substr(item ? A[j][item] : A[j], 1, L), &#039;On&#039;) = 0 ? j : 0
}

GetYD(req, &amp;Response, &amp;status, &amp;dir?, &amp;token?, limit := 1000, offset := 0) {	; запрос к облаку
	url := &#039;https://cloud-api.yandex.net/v1/disk&#039; . (req = &#039;p_res&#039; || req = &#039;p_nam&#039; ? &#039;/public/resources?public_key=&#039; . token : &#039;&#039;)
	if req = &#039;res&#039; || req = &#039;p_res&#039;
		P := &#039;_embedded.items.&#039;, fields := &#039;fields=&#039; P &#039;type%2C,&#039; P &#039;path%2C,&#039; P &#039;name%2C,&#039; P &#039;created&#039;
	switch {
	case req = &#039;res&#039;	: url .= &#039;/resources?&#039; fields &#039;&amp;limit=&#039; limit &#039;&amp;path=&#039; UrlCodec.Encode(dir)
	case req = &#039;disk&#039;	: url .= &#039;?fields=total_space%2Cused_space&#039;
	case req = &#039;p_res&#039;	: url .= &#039;&amp;&#039; fields &#039;&amp;limit=&#039; limit &#039;&amp;path=&#039; UrlCodec.Encode(dir)
	case req = &#039;p_nam&#039;	: url .= &#039;&amp;fields=name&#039;
	case req = &#039;plane&#039;	: url .= &#039;/resources/files?limit=&#039; limit &#039;&amp;offset=&#039; offset &#039;&amp;fields=items.path%2Citems.created&#039;
	Default:
		Response := &#039;Неверный запрос&#039;, status := -1
		return 0
	}
	headers := Map(&quot;Accept&quot;, &quot;application/json&quot;)
	if instr(&#039;res disk plane&#039;, req)
		headers[&quot;Authorization&quot;] := token
	Response := WebRequest(url,, headers,,, &amp;status)
	return status = 200
}

; Функция для рекурсивного обхода списка директорий и построения дерева
DirTreeText(dir, prefix, isLast := true, depth := 0, created := &#039;&#039;) {
	global tree, info, List
	static UTCPlus := DateDiff(A_Now, A_NowUTC, &#039;H&#039;)

	if 	NOT idx := SASearch(List, &amp;dir, &#039;path&#039;) {
		MsgBox &#039;Не найдена папка`n&#039; dir
		ExitApp
	}
	; список папок, вложенных в папку dir
	dirs := []
	while idx &lt;= List.Length &amp;&amp; substr(List[idx][&#039;path&#039;], 1, strlen(dir)) = dir {
		if subDirEndPos := InStr(List[idx][&#039;path&#039;], &#039;/&#039;, &#039;On&#039;, strlen(dir) + 1) {
			; subDirEndPos = 0 для папки dir, поэтому она не попадёт в dirs
			path := SubStr(List[idx][&#039;path&#039;], 1, subDirEndPos)
			if !SASearch(dirs, &amp;path, &#039;path&#039;)
				dirs.Push Map(&#039;path&#039;, path
				, &#039;created&#039;, FormatTime(DateAdd(RegExReplace(substr(List[idx][&#039;created&#039;], 1, -6), &#039;-|T|:&#039;), UTCPlus, &#039;H&#039;), &#039;dd.MM.yy HH:mm&#039;))
		}
		idx++
	}

	if depth {
		namePos := instr(dir, &#039;/&#039;, &#039;On&#039;,, -2)
		currentFolder := SubStr(dir, namePos+1, StrLen(dir)-NamePos-1)
		tree .= prefix (isLast ? &#039;└───&#039; : &#039;├───&#039;) currentFolder &#039;`t`t&#039; created &#039;`n&#039;
		prefix := prefix (isLast ? &#039;    &#039; : &#039;│   &#039;)
	}

    for idx, subDir in dirs
        DirTreeText subDir[&#039;path&#039;], prefix, idx = dirs.Length, 1, subDir[&#039;created&#039;]
}

FileName := A_ScriptDir &#039;\YandexToken.txt&#039;
try
    FileObj := FileOpen(FileName, &quot;r&quot;)
catch as Err {
    MsgBox &quot;Не читается файл с токеном `n&quot; FileName
        . &quot;`n`n&quot; Type(Err) &quot;: &quot; Err.Message
    ExitApp
}
token := &quot;OAuth &quot; rtrim(FileObj.Read(), &#039;`r`n&#039;)
FileObj.Close()

startFolder := &#039;/&#039;
if !GetYD(&#039;disk&#039;, &amp;Response, &amp;status,, &amp;token) {
	MsgBox &#039;Ошибка &#039; status &#039; на информации о диске`n&#039; Response
	ExitApp
}

DiskInfo := LightJson.Parse(Response)
SpaceFree := (Integer(DiskInfo[&#039;total_space&#039;])-Integer(DiskInfo[&#039;used_space&#039;]))&gt;&gt;&gt;20 &#039; GiB свободно из &#039; Integer(DiskInfo[&#039;total_space&#039;])&gt;&gt;&gt;20
DriveLabel := &#039;YD&#039;

outputFile := A_ScriptDir &#039;\&#039; DriveLabel &#039;.txt&#039;

; информационное окно
BarWidth := 300
global Info := Gui(&quot;+LastFound&quot;, &#039;Info - &#039; A_ScriptName)
Info.AddText &#039;vText1 r2 w&#039; BarWidth, &#039;Построение дерева...&#039;
Info.AddButton &#039;vButton Default w&#039; BarWidth, &#039;Cancel&#039;
Info[&#039;Button&#039;].OnEvent(&#039;Click&#039;, (*) =&gt; ExitApp())
Info.AddStatusBar &#039;vStatus&#039;
Info.Show &#039;w&#039; BarWidth+Info.MarginX*2
SetTimer Wink, 1000
Wink() {
	static ColorInd := 1, Colour := [&#039;cDefault&#039;, &#039;cWhite&#039;], Period := [1000, 500]
	SetTimer , Period[ColorInd+1]
	Info[&#039;Text1&#039;].Opt(Colour[ColorInd+1])
	ColorInd := !ColorInd
}

Time1 := A_TickCount
limit := 3000, offset := 0
global List := []

loop {
	Info[&#039;Status&#039;].SetText(&#039;Запрос, offset=&#039; offset)
	if !GetYD(&#039;plane&#039;, &amp;Response, &amp;status,, &amp;token, limit, offset) {
		MsgBox &#039;Ошибка &#039; status &#039; на получении списка`n&#039; Response
		ExitApp
	}
	Info[&#039;Status&#039;].SetText(&#039;Обработка, offset=&#039; offset)
	Lst := LightJson.Parse(Response)[&#039;items&#039;]

	for idx, Item in Lst ; убираем имена файлов и префикс disk:
		Lst[idx][&#039;path&#039;] := SubStr(Item[&#039;path&#039;], 6, instr(Item[&#039;path&#039;], &#039;/&#039;, &#039;On&#039;, -1) - 5)

	qSortAMap Lst, &#039;path&#039;

	idx := 1
	while idx &lt;= Lst.Length { ;  неодинаковые добавляем в List
		if substr(Lst[idx][&#039;path&#039;], 1, StrLen(startFolder)) != startFolder {
			idx++
			continue ; ненужные пропускаем
		}
		List.Push Lst[idx]
		path := Lst[idx][&#039;path&#039;]
		while ++idx &lt;= Lst.Length &amp;&amp; Lst[idx][&#039;path&#039;] = path { ; одинаковые пропускаем, корректируя дату
			if StrCompare(Lst[idx][&#039;created&#039;], List[List.Length][&#039;created&#039;], &#039;On&#039;) &lt; 0
				List[List.Length][&#039;created&#039;] := Lst[idx][&#039;created&#039;]
		}
	}
	offset += limit
} until lst.Length &lt; limit

if offset &gt; limit { ; удаляем одинаковые из List, корректируя дату
	Info[&#039;Status&#039;].SetText(&#039;Обработка...&#039;)
	qSortAMap List, &#039;path&#039;
	idx := 2
	while idx &lt;= List.Length
		if List[idx][&#039;path&#039;] = List[idx-1][&#039;path&#039;] {
			if StrCompare(List[idx][&#039;created&#039;], List[idx-1][&#039;created&#039;], &#039;On&#039;) &lt; 0
				List[idx-1][&#039;created&#039;] := List[idx][&#039;created&#039;]
			List.RemoveAt(idx)
		} else idx++
}

; теперь строим дерево
Info[&#039;Status&#039;].SetText(&#039;Строим...&#039;)
global tree := DriveLabel &#039;, &#039;  SpaceFree &#039;`n&#039; startFolder &#039;`n&#039;
DirTreeText startFolder, DriveLabel
statistics := &#039;Затрачено &#039; (A_TickCount - Time1) // 1000 &#039; с&#039;
tree .= &#039;`n&#039; statistics &#039;`n&#039;

; Сохраняем в файл
try	FileDelete outputFile
try FileAppend tree, outputFile, &#039;UTF-8&#039;
catch as e {
	MsgBox &#039;Ошибка при записи в файл: &#039; e.Message
	ExitApp
}

SetTimer Wink, 0
Info[&#039;Text1&#039;].Opt(&#039;cDefault&#039;)
Info[&#039;Text1&#039;].Text := statistics &#039;. Сохранено в `n&#039; outputFile
Info[&#039;Status&#039;].SetText(&#039;Готово&#039;)
Info[&#039;Button&#039;].Text := &#039;OK&#039;
Info[&#039;Button&#039;].GetPos(&amp;X, &amp;Y, &amp;Width, &amp;Height)
WinActivate
MouseMove X + Width // 2, Y + Height // 2
SoundPlay &quot;*-1&quot;
</code></pre></div><p>Небыстрый вариант<br /></p><div class="codebox"><pre><code>; для создания каталога публичного ресурса на яндекс-диске или каталога своего яндекс-диска
; если на запрос публичного URL вводится пустое значение, токен берётся из файла YandexToken.txt, расположенного рядом со скриптом
#Requires AutoHotkey v2
#DllLoad &#039;WinHttp.dll&#039;
#Include &lt;LightJson&gt;	; https://forum.script-coding.com/viewtopic.php?id=18483
#Include &lt;WebRequest&gt;	; https://forum.script-coding.com/viewtopic.php?pid=162651#p162651
#Include &lt;UrlCodec&gt;		; https://forum.script-coding.com/viewtopic.php?pid=162669#p162669

GetYD(req, &amp;Response, &amp;status, &amp;dir?, &amp;token?, limit := 1000, offset := 0) {	; запрос к облаку
	url := &#039;https://cloud-api.yandex.net/v1/disk&#039; . (req = &#039;p_res&#039; || req = &#039;p_nam&#039; ? &#039;/public/resources?public_key=&#039; . token : &#039;&#039;)
	if req = &#039;res&#039; || req = &#039;p_res&#039;
		P := &#039;_embedded.items.&#039;, fields := &#039;fields=&#039; P &#039;type%2C,&#039; P &#039;path%2C,&#039; P &#039;name%2C,&#039; P &#039;created&#039;
	switch {
	case req = &#039;res&#039;	: url .= &#039;/resources?&#039; fields &#039;&amp;limit=&#039; limit &#039;&amp;path=&#039; UrlCodec.Encode(dir)
	case req = &#039;disk&#039;	: url .= &#039;?fields=total_space%2Cused_space&#039;
	case req = &#039;p_res&#039;	: url .= &#039;&amp;&#039; fields &#039;&amp;limit=&#039; limit &#039;&amp;path=&#039; UrlCodec.Encode(dir)
	case req = &#039;p_nam&#039;	: url .= &#039;&amp;fields=name&#039;
	case req = &#039;plane&#039;	: url .= &#039;/resources/files?limit=&#039; limit &#039;&amp;offset=&#039; offset &#039;&amp;fields=items.path%2Citems.created&#039;
	Default:
		Response := &#039;Неверный запрос&#039;, status := -1
		return 0
	}
	headers := Map(&quot;Accept&quot;, &quot;application/json&quot;)
	if instr(&#039;res disk plane&#039;, req)
		headers[&quot;Authorization&quot;] := token
	Response := WebRequest(url,, headers,,, &amp;status)
	return status = 200
}

; Функция для рекурсивного обхода директории и построения дерева
DirTreeText(dir, prefix, isLast := true, depth := 0, name := &#039;&#039;, created := &#039;&#039;) {
	global tree, info, token
	static FoldersCount := 0, AlwaysContinue := false, UTCPlus := DateDiff(A_Now, A_NowUTC, &#039;H&#039;), req := substr(token, 1, 6) = &quot;OAuth &quot; ? &#039;res&#039; : &#039;p_res&#039;

	dirs := []
	if GetYD(req, &amp;Response, &amp;status, &amp;dir, &amp;token) {
		for idx, Item in LightJson.Parse(Response)[&quot;_embedded&quot;][&quot;items&quot;]
			if Item[&#039;type&#039;] = &#039;dir&#039;
				dirs.Push Map(&#039;path&#039;, Item[&#039;path&#039;], &#039;name&#039;, Item[&#039;name&#039;]
				, &#039;created&#039;, FormatTime(DateAdd(RegExReplace(substr(Item[&#039;created&#039;], 1, -6), &#039;-|T|:&#039;), UTCPlus, &#039;H&#039;), &#039;dd.MM.yy HH:mm&#039;))
	}
	else {
		if !AlwaysContinue {
			WhatToDo := MsgBox(&#039;Ошибка &#039; status &#039; на папке `n&#039; dir &#039;`n&#039; Response &#039;`n`n&#039; &quot;
			(
			Да`t- продолжить и больше не спрашивать;
			Нет`t- продолжить до следующей ошибки;
			Отмена`t- прекратить.
			)&quot;,, &#039;YNC Icon?&#039;)
			if WhatToDo = &#039;Cancel&#039;
				ExitApp
			AlwaysContinue := WhatToDo = &#039;Yes&#039;
		}
		name := dir &#039;`n&#039; UrlCodec.Encode(dir)
		created := &#039;ошибка&#039;
	}
	if depth {
		tree .= prefix (isLast ? &#039;└───&#039; : &#039;├───&#039;) name &#039;`t`t&#039; created &#039;`n&#039;
		Info[&#039;Status&#039;].SetText(&#039;Папка № &#039; . ++FoldersCount, 1), Info[&#039;Status&#039;].SetText(name, 2)
		prefix := prefix (isLast ? &#039;    &#039; : &#039;│   &#039;)
	} else	Info[&#039;Progress&#039;].Opt(&#039;Range0-&#039; dirs.Length)

    for idx, subDir in dirs {
		if !depth
			Info[&#039;Progress&#039;].Value++
        DirTreeText subDir[&#039;path&#039;], prefix, idx = dirs.Length, 1, subDir[&#039;name&#039;], subDir[&#039;created&#039;]
	}
}

startFolder := &#039;/&#039;
IB := InputBox(&quot;Публичный URL&quot;,,&#039;h100&#039;)
if IB.Result = &quot;Cancel&quot;
    ExitApp
global token
if token := IB.Value {
	if !GetYD(&#039;p_nam&#039;, &amp;Response, &amp;status,, &amp;token) {
		MsgBox &#039;Ошибка &#039; status &#039; на информации о публичном имени`n&#039; Response
		ExitApp
	}
	DriveLabel := &#039;YD-&#039; LightJson.Parse(Response)[&#039;name&#039;]
	SpaceFree := &#039;&#039;
	IB := InputBox(&quot;Имя выходного файла&quot;,,&#039;h100&#039;, DriveLabel)
	if IB.Result = &quot;Cancel&quot;
		ExitApp
	DriveLabel := IB.Value
} else {
	FileName := A_ScriptDir &#039;\YandexToken.txt&#039;
	try
		FileObj := FileOpen(FileName, &quot;r&quot;)
	catch as Err {
		MsgBox &quot;Не читается файл с токеном `n&quot; FileName
        . &quot;`n`n&quot; Type(Err) &quot;: &quot; Err.Message
		ExitApp
	}
	token := &quot;OAuth &quot; rtrim(FileObj.Read(), &#039;`r`n&#039;)
	FileObj.Close()
	if !GetYD(&#039;disk&#039;, &amp;Response, &amp;status,, &amp;token) {
		MsgBox &#039;Ошибка &#039; status &#039; на информации о диске`n&#039; Response
		ExitApp
	}
	DiskInfo := LightJson.Parse(Response)
	SpaceFree := (Integer(DiskInfo[&#039;total_space&#039;])-Integer(DiskInfo[&#039;used_space&#039;]))&gt;&gt;20 &#039; GiB свободно из &#039; Integer(DiskInfo[&#039;total_space&#039;])&gt;&gt;20
	DriveLabel := &#039;YD&#039;
}

outputFile := A_ScriptDir &#039;\&#039; DriveLabel &#039;.txt&#039;

; информационное окно
BarWidth := 300
global Info := Gui(&quot;+LastFound&quot;, &#039;Info - &#039; A_ScriptName)
Info.AddText &#039;vText1 r2 w&#039; BarWidth, &#039;Построение дерева...&#039;
Info.AddProgress &#039;vProgress h10 w&#039; BarWidth
Info.AddButton &#039;vButton Default w&#039; BarWidth, &#039;Cancel&#039;
Info[&#039;Button&#039;].OnEvent(&#039;Click&#039;, (*) =&gt; ExitApp())
Info.AddStatusBar &#039;vStatus&#039;
Info[&#039;Status&#039;].SetParts(85)
Info.Show &#039;w&#039; BarWidth+Info.MarginX*2

; Построение дерева
global tree := DriveLabel &#039;, &#039;  SpaceFree &#039;`n&#039; startFolder &#039;`n&#039;
Time1 := A_TickCount
DirTreeText startFolder, DriveLabel
statistics := &#039;Затрачено &#039; (A_TickCount - Time1) // 1000 &#039; с&#039;
tree .= &#039;`n&#039; statistics &#039;`n&#039;

; Сохраняем в файл
try	FileDelete outputFile
try FileAppend tree, outputFile, &#039;UTF-8&#039;
catch as e {
	MsgBox &#039;Ошибка при записи в файл: &#039; e.Message
	ExitApp
}

Info[&#039;Text1&#039;].Text := statistics &#039;. Сохранено в `n&#039; outputFile
Info[&#039;Button&#039;].Text := &#039;OK&#039;
Info[&#039;Button&#039;].GetPos(&amp;X, &amp;Y, &amp;Width, &amp;Height)
WinActivate
MouseMove X + Width // 2, Y + Height // 2
SoundPlay &quot;*-1&quot;
</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Mon, 08 Sep 2025 07:59:33 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162693#p162693</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162690#p162690</link>
			<description><![CDATA[<p>Быстрый вариант для своего яндекс-диска<br />Del</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Sun, 07 Sep 2025 07:12:12 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162690#p162690</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162673#p162673</link>
			<description><![CDATA[<p>Выбрал вариант JS, он побыстрее</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Thu, 04 Sep 2025 05:10:57 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162673#p162673</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162669#p162669</link>
			<description><![CDATA[<p>Кодировать URL надежнее не с помощью ручного парсинга, а с помощью специального API. Например: <br /></p><div class="codebox"><pre><code>#Requires AutoHotkey v2.0

encoded1 := UrlCodec.Encode(&#039;https://forum.script-coding.com/Привет&#039;)
encoded2 := UrlCodec.Encode(&#039;https://forum.script-coding.com/Привет&#039;, false)
decoded1 := UrlCodec.Decode(encoded1)
decoded2 := UrlCodec.Decode(encoded2)

MsgBox encoded1 . &#039;`n`n&#039;
     . encoded2 . &#039;`n`n&#039;
     . decoded1 . &#039;`n&#039;
     . decoded2

class UrlCodec
{
    static Encode(str, segment := true) {
        static E_POINTER := 0x80004003
             , URL_ESCAPE_PERCENT             := 0x00001000
             , URL_ESCAPE_SEGMENT_ONLY        := 0x00002000
             , URL_ESCAPE_AS_UTF8             := 0x00040000
             , URL_ESCAPE_ASCII_URI_COMPONENT := 0x00080000

        flags := ( URL_ESCAPE_PERCENT | URL_ESCAPE_ASCII_URI_COMPONENT
                 | URL_ESCAPE_AS_UTF8 | (segment ? URL_ESCAPE_SEGMENT_ONLY : 0) )

        req := StrLen(str)
        Loop 2 {
            buf := Buffer(req * 2)
            r := DllCall(&#039;Shlwapi\UrlEscape&#039;, &#039;Str&#039;, str, &#039;Ptr&#039;, buf, &#039;UInt*&#039;, &amp;req, &#039;UInt&#039;, flags, &#039;UInt&#039;)
            if !(r = E_POINTER || r = 0) {
                throw Error(&#039;UrlEscape failed, error: &#039; . Format(&#039;{:#x}&#039;, r))
            }
        } until r == 0
        return StrGet(buf)
    }

    static Decode(encoded) {
        static E_POINTER := 0x80004003, flags := (URL_UNESCAPE_AS_UTF8 := 0x00040000)
        req := StrLen(encoded)
        Loop 2 {
            buf := Buffer(req * 2)
            r := DllCall(&#039;Shlwapi\UrlUnescape&#039;, &#039;Str&#039;, encoded, &#039;Ptr&#039;, buf, &#039;UInt*&#039;, &amp;req, &#039;UInt&#039;, flags, &#039;UInt&#039;)
            if !(r = E_POINTER || r = 0) {
                throw Error(&#039;UrlUnescape failed, error: &#039; . Format(&#039;{:#x}&#039;, r))
            }
        } until r == 0
        return StrGet(buf)
    }
}</code></pre></div><p>Или так:<br /></p><div class="codebox"><pre><code>class UrlCodec
{
    static __New() {
        static document := &#039;&#039;
        document := ComObject(&#039;htmlfile&#039;)
        document.write(&#039;&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=9&quot;&gt;&#039;)
        this.JS := document.parentWindow
        (document.documentMode &lt; 9 &amp;&amp; this.JS.execScript())
    }
    static Encode(str, component := true) =&gt; this.JS.%&#039;encodeURI&#039; . (component ? &#039;Component&#039; : &#039;&#039;)%(str)
    static Decode(str, component := true) =&gt; this.JS.%&#039;decodeURI&#039; . (component ? &#039;Component&#039; : &#039;&#039;)%(str)
}</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Wed, 03 Sep 2025 22:03:34 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162669#p162669</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162666#p162666</link>
			<description><![CDATA[<p>Зря грешил на rest api яндекс, на мне грех. В функции URIEncode было &quot;%{:X}&quot; вместо правильного &quot;%{:02X}&quot;. Сейчас что не работало - работает.</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Wed, 03 Sep 2025 05:11:23 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162666#p162666</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162651#p162651</link>
			<description><![CDATA[<p>ResponseText не поддерживает юникодные символы. Чтобы избежать кракозябров, нужно читать данные из свойства responseBody, возвращающего бинарный массив, который потом можно интерпретировать, как строку в кодировке UTF-8. Для простых случаев я использую такую функцию, где это реализовано:<br /></p><div class="codebox"><pre><code>WebRequest(url, method := &#039;GET&#039;, headersMap := &#039;&#039;, retBinary := false, body?, &amp;status?) {
    Whr := ComObject(&#039;WinHttp.WinHttpRequest.5.1&#039;)
    Whr.Open(method, url, true)
    if headersMap is Map {
        for name, value in headersMap
            Whr.SetRequestHeader(name, value)
    }
    Whr.Send(body ?? &#039;&#039;)
    Whr.WaitForResponse()
    status := Whr.status
    if SafeArray := Whr.responseBody {
        pData := NumGet(ComObjValue(SafeArray) + 8 + A_PtrSize, &#039;Ptr&#039;)
        length := SafeArray.MaxIndex() + 1
        if !retBinary {
            return StrGet(pData, length, &#039;UTF-8&#039;)
        }
        DllCall(&#039;RtlMoveMemory&#039;, &#039;Ptr&#039;, data := Buffer(length), &#039;Ptr&#039;, pData, &#039;Ptr&#039;, length)
        return data
    }
    return &#039;&#039;
}</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Sat, 30 Aug 2025 16:11:47 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162651#p162651</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162650#p162650</link>
			<description><![CDATA[<p>С LightJson стало ещё на несколько секунд быстрее</p><p>Есть недочёт. При ошибке WinHttp.WinHttpRequest.5.1 в ответе показывает тарабарщину:<br />{&quot;error&quot;:&quot;NotFoundError&quot;,&quot;description&quot;:&quot;Not Found&quot;,&quot;message&quot;:&quot;? ?µN?N?N?N? ???µ ???°?????µ??.&quot;}<br />Можно с этим что-то сделать?</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Sat, 30 Aug 2025 08:04:45 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162650#p162650</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162646#p162646</link>
			<description><![CDATA[<p>Программировать - приятно! ))</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Thu, 28 Aug 2025 18:56:55 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162646#p162646</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162645#p162645</link>
			<description><![CDATA[<p>Насколько я понял по сообществу форума на autohotkey.com, среди пользователей AHK многие уже в зрелом возрасте. Приятно, что люди выбирают программирование в качестве хобби, а не сидение на скамейке во дворе. <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" /></p>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Thu, 28 Aug 2025 18:42:59 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162645#p162645</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162644#p162644</link>
			<description><![CDATA[<p>Да, с WinHttp получилось даже быстрее, чем в варианте с подключённым диском: 187 с против 194 )))</p><p>Если что, я пенсионер, вне программистского сообщества с 1988 г. Последний рабочий язык - visual foxpro. Для меня многое в новинку, буду премного благодарен за подсказки.</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Thu, 28 Aug 2025 09:42:29 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162644#p162644</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162643#p162643</link>
			<description><![CDATA[<p>В AHK для веб-запросов не нужно использовать сторонние приложения. Смотрите примеры с ком-объектом WinHttp.WinHttpRequest.5.1.</p>]]></description>
			<author><![CDATA[null@example.com (teadrinker)]]></author>
			<pubDate>Wed, 27 Aug 2025 20:36:43 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162643#p162643</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162642#p162642</link>
			<description><![CDATA[<p>Ну вот, сделал на rest api яндекс. Получилось медленнее больше чем на минуту. Не думаю, что будет быстрее не через curl, а непосредственно через библиотеку.</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Tue, 26 Aug 2025 21:34:31 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162642#p162642</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162638#p162638</link>
			<description><![CDATA[<p>Приступил к rest api яндекс. Ввожу строку для curl с полигона и получаю ошибки. Может, кто подскажет, в чём дело?<br /></p><div class="codebox"><pre><code>D:\Мои документы\AutoHotkey&gt;curl --version
curl 8.15.0 (x86_64-w64-mingw32) libcurl/8.15.0 OpenSSL/3.5.1 zlib/1.3.1.zlib-ng libidn2/2.3.8 libpsl/0.21.5
Release-Date: 2025-07-16
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtsp smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS HSTS HTTPS-proxy IDN IPv6 Largefile libz PSL SSL threadsafe TLS-SRP Unicode UnixSockets

D:\Мои документы\AutoHotkey&gt;curl -X GET --header &#039;Accept: application/json&#039; --header &#039;Authorization: OAuth &lt;токен&gt; &#039;https://cloud-api.yandex.net/v1/disk/resources?path=%2F&#039;
curl: (6) Could not resolve host: application
curl: (6) Could not resolve host: OAuth
curl: (3) URL rejected: Bad hostname
curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535</code></pre></div><p>Проблему решил заменой &#039; на &quot; )))</p>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Sat, 23 Aug 2025 11:50:09 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162638#p162638</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162623#p162623</link>
			<description><![CDATA[<p><strong>Malcev</strong><br />Спасибо, попробую. Пока нашёл другое решение: обход яндекс-диска с задержкой. 400 мс вроде хватает.<br /></p><div class="codebox"><pre><code>/*
Программа для создания каталога в виде дерева папок, начиная с выбранной.
Сетевые диски (&quot;Network&quot;) обходятся с подобранной (и, возможно, не всегда достоточной) задержкой.
Для яндекс-дисков лучше пользоваться скриптом YDPlane или YDTree.
teadrinker, Thanks a lot!
*/
#Requires AutoHotkey v2
; Функция для рекурсивного обхода директории и построения дерева
DirTreeText(dir, prefix, isLast := true, depth := 0) {
	global tree, info
	static FoldersCount := 0, Network := substr(prefix, 1, 4) = &#039;Net_&#039;

	dirs := []
    Loop files dir &#039;\*&#039;, &#039;D&#039;
        dirs.Push A_LoopFilePath

	if depth {
		SplitPath dir, &amp;name
		Time := &#039;&#039;
		try Time := FormatTime(FileGetTime(dir, &#039;C&#039;), &#039;dd.MM.yy HH:mm&#039;)
		tree .= prefix (isLast ? &#039;└───&#039; : &#039;├───&#039;) name A_Tab A_Tab Time &#039;`n&#039;
		Info[&#039;Status&#039;].SetText(&#039;Папка № &#039; . ++FoldersCount, 1), Info[&#039;Status&#039;].SetText(name, 2)
		prefix := prefix (isLast ? &#039;    &#039; : &#039;│   &#039;)
	} else	Info[&#039;Progress&#039;].Opt(&#039;Range0-&#039; dirs.Length)

    for idx, subDir in dirs {
		if !depth
			Info[&#039;Progress&#039;].Value++
		if Network
			sleep 400
        DirTreeText subDir, prefix, idx = dirs.Length, 1
	}
}

; Основная часть программы
if NOT startFolder :=  A_Args.Length ? A_Args[1] : RegExReplace(DirSelect(, 0, &#039;Выберите начальную папку для построения дерева&#039;), &#039;\\$&#039;)
	ExitApp
SplitPath startFolder,,,,, &amp;Drive
if DriveGetType(Drive) = &#039;Network&#039; {
	DriveLabel := &#039;Net_&#039; substr(Drive, 1, -1)
	SpaceFree := &#039;&#039;
} else {
	DriveLabel := DriveGetLabel(Drive)
	SpaceFree := DriveGetSpaceFree(Drive)//1024  &#039; GiB свободно из &#039; DriveGetCapacity(Drive)//1024
}
outputFile := A_ScriptDir &#039;\&#039; DriveLabel &#039;.txt&#039;
if NOT A_Args.Length and NOT outputFile := FileSelect(&#039;S16&#039;, outputFile, &#039;Файл для каталога&#039;, &#039;Documents (*.txt)&#039;)
	ExitApp
global tree := &#039;Том: &#039; DriveLabel &#039;, &#039;  SpaceFree &#039;`n&#039; startFolder &#039;`n&#039;

; информационное окно
BarWidth := 300
global Info := Gui(&quot;+LastFound&quot;, &#039;Info - &#039; A_ScriptName)
Info.AddText &#039;vText1 r2 w&#039; BarWidth, &#039;Построение дерева...&#039;
Info.AddProgress &#039;vProgress h10 w&#039; BarWidth
Info.AddButton &#039;vButton Default w&#039; BarWidth, &#039;Cancel&#039;
Info[&#039;Button&#039;].OnEvent(&#039;Click&#039;, (*) =&gt; ExitApp())
Info.AddStatusBar &#039;vStatus&#039;
Info[&#039;Status&#039;].SetParts(85)
Info.Show &#039;w&#039; BarWidth+Info.MarginX*2

; Построение дерева
Time1 := A_TickCount
DirTreeText startFolder, DriveLabel
statistics := &#039;Затрачено &#039; (A_TickCount - Time1) // 1000 &#039; с&#039;
tree .= &#039;`n&#039; statistics &#039;`n&#039;

; Сохраняем в файл
try	FileDelete outputFile
try FileAppend tree, outputFile, &#039;UTF-8&#039;
catch as e {
	MsgBox &#039;Ошибка при записи в файл: &#039; e.Message
	ExitApp
}

Info[&#039;Text1&#039;].Text := statistics &#039;. Сохранено в `n&#039; outputFile
Info[&#039;Button&#039;].Text := &#039;OK&#039;
Info[&#039;Button&#039;].GetPos(&amp;X, &amp;Y, &amp;Width, &amp;Height)
WinActivate
MouseMove X + Width // 2, Y + Height // 2
SoundPlay &quot;*-1&quot;
</code></pre></div>]]></description>
			<author><![CDATA[null@example.com (haridev)]]></author>
			<pubDate>Sun, 03 Aug 2025 04:17:42 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162623#p162623</guid>
		</item>
		<item>
			<title><![CDATA[Re: AHK: v2 loop files на яндекс-диске]]></title>
			<link>https://forum.script-coding.com/viewtopic.php?pid=162620#p162620</link>
			<description><![CDATA[<p>Задаете этот вопрос чат жпт, он вам дает пример rest api yandex.<br />Вызываете эти get, post запросы на ахк.<br />В принципе чат жпт и код может готовый вам на автохотки состряпать.</p>]]></description>
			<author><![CDATA[null@example.com (Malcev)]]></author>
			<pubDate>Fri, 01 Aug 2025 19:14:41 +0000</pubDate>
			<guid>https://forum.script-coding.com/viewtopic.php?pid=162620#p162620</guid>
		</item>
	</channel>
</rss>
