mirror of
https://github.com/nkanaev/yarr.git
synced 2025-11-07 09:59:38 +00:00
Compare commits
76 Commits
57ea83cf4f
...
gh-actions
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
348693fa95 | ||
|
|
b40c6fc9e4 | ||
|
|
73fd637b23 | ||
|
|
b8afa82a81 | ||
|
|
097a2da5cb | ||
|
|
e6d32946c1 | ||
|
|
fe4eaa4b8d | ||
|
|
48a671b285 | ||
|
|
011c9c7668 | ||
|
|
f06fc1f750 | ||
|
|
0e88d4284d | ||
|
|
1615c6869f | ||
|
|
800f43b299 | ||
|
|
15bff0a0c4 | ||
|
|
e1481f4aac | ||
|
|
7ef97ee6db | ||
|
|
d785fe4c5a | ||
|
|
5254df53dc | ||
|
|
7301eab99c | ||
|
|
ad138c3017 | ||
|
|
b09c95d7ea | ||
|
|
64611a0dd3 | ||
|
|
321ad7608f | ||
|
|
2a8b6ea935 | ||
|
|
e9cbea500b | ||
|
|
223039b2c6 | ||
|
|
7402dfc4e6 | ||
|
|
6b12715506 | ||
|
|
2dc58c5c8e | ||
|
|
0cef51c6ac | ||
|
|
2a4d974965 | ||
|
|
f71792d6a5 | ||
|
|
b571042c5d | ||
|
|
349c966c63 | ||
|
|
4a42b239cc | ||
|
|
b9b3d2350c | ||
|
|
b13cd85f0b | ||
|
|
daffd721eb | ||
|
|
24232d72e9 | ||
|
|
4983e18e23 | ||
|
|
e1954e4cba | ||
|
|
58420ae52b | ||
|
|
b01f71de1a | ||
|
|
379aaed39e | ||
|
|
dc20932060 | ||
|
|
96835ebd33 | ||
|
|
c896f779b5 | ||
|
|
5f606b1c40 | ||
|
|
9d5b8d99f7 | ||
|
|
13c047fc21 | ||
|
|
55751b3eb6 | ||
|
|
b961502a17 | ||
|
|
a895145586 | ||
|
|
5aec3b4dab | ||
|
|
d787060a24 | ||
|
|
c1a29418eb | ||
|
|
17847f999c | ||
|
|
3adcddc70c | ||
|
|
c76ff26bd6 | ||
|
|
50f8648f64 | ||
|
|
5f82a9e339 | ||
|
|
3278ba4eac | ||
|
|
9fc72f8b68 | ||
|
|
b7b707bd43 | ||
|
|
7cf27e0fde | ||
|
|
66f2a973a3 | ||
|
|
7ecbbff18a | ||
|
|
850ce195a0 | ||
|
|
479aebd023 | ||
|
|
9b178d1fb3 | ||
|
|
3ab098db5c | ||
|
|
6d16e93008 | ||
|
|
98934daee4 | ||
|
|
259474cae9 | ||
|
|
1e65a7951b | ||
|
|
bed5640366 |
38
.github/workflows/build-docker-image
vendored
Normal file
38
.github/workflows/build-docker-image
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
name: Publish Docker Image
|
||||
on:
|
||||
push:
|
||||
tags: [ 'v*.*.*', 'v*.*', 'v*', 'latest' ]
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: nkanaev/yarr
|
||||
jobs:
|
||||
build-and-push-image:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
|
||||
with:
|
||||
context: .
|
||||
file: ./etc/dockerfile
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
157
.github/workflows/build.yml
vendored
157
.github/workflows/build.yml
vendored
@@ -1,8 +1,14 @@
|
||||
name: build
|
||||
name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: ['v*', 'test*']
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch:
|
||||
workflow_run:
|
||||
workflows: [Test]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
build_macos:
|
||||
@@ -18,7 +24,7 @@ jobs:
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
@@ -27,7 +33,7 @@ jobs:
|
||||
- name: "Build"
|
||||
run: make build_macos
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macos
|
||||
path: _output/macos/yarr.app
|
||||
@@ -45,7 +51,7 @@ jobs:
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
@@ -54,7 +60,7 @@ jobs:
|
||||
- name: "Build"
|
||||
run: make build_windows
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows
|
||||
path: _output/windows/yarr.exe
|
||||
@@ -72,38 +78,99 @@ jobs:
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
|
||||
key: ${{ runner.os }}-amd64-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-
|
||||
${{ runner.os }}-go-amd64
|
||||
- name: "Build"
|
||||
run: make build_linux
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux
|
||||
path: _output/linux/yarr
|
||||
|
||||
build_linux-arm:
|
||||
name: Build for Linux ARM
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: >
|
||||
sudo apt-get install -y
|
||||
gcc-arm-linux-gnueabihf
|
||||
libc6-dev-armhf-cross
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-armv7-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-armv7
|
||||
- name: "Build"
|
||||
env:
|
||||
CC: arm-linux-gnueabihf-gcc
|
||||
GOARCH: arm
|
||||
GOARM: 7
|
||||
run: make build_linux
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux_arm
|
||||
path: _output/linux/yarr
|
||||
|
||||
build_linux-arm64:
|
||||
name: Build for Linux ARM64
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: >
|
||||
sudo apt-get install -y
|
||||
gcc-aarch64-linux-gnu
|
||||
libc6-dev-arm64-cross
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: "Setup Go"
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '^1.17'
|
||||
- name: Cache Go Modules
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/go/pkg/mod
|
||||
key: ${{ runner.os }}-arm64-go-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-go-arm64
|
||||
- name: "Build"
|
||||
env:
|
||||
CC: aarch64-linux-gnu-gcc
|
||||
GOARCH: arm64
|
||||
run: make build_linux
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux_arm64
|
||||
path: _output/linux/yarr
|
||||
|
||||
create_release:
|
||||
name: Create Release
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ !contains(github.ref, 'test') }}
|
||||
needs: [build_macos, build_windows, build_linux]
|
||||
if: ${{ startsWith(github.ref, 'refs/tags/') && !contains(github.ref, 'test') }}
|
||||
needs: [build_macos, build_windows, build_linux, build_linux-arm, build_linux-arm64]
|
||||
steps:
|
||||
- name: Create Release
|
||||
uses: actions/create-release@v1
|
||||
id: create_release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: ${{ github.ref }}
|
||||
draft: true
|
||||
prerelease: true
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
path: .
|
||||
- name: Preparation
|
||||
@@ -111,34 +178,24 @@ jobs:
|
||||
ls -R
|
||||
chmod u+x macos/Contents/MacOS/yarr
|
||||
chmod u+x linux/yarr
|
||||
chmod u+x linux_arm/yarr
|
||||
chmod u+x linux_arm64/yarr
|
||||
|
||||
mv macos yarr.app && zip -r yarr-macos.zip yarr.app
|
||||
mv windows/yarr.exe . && zip yarr-windows.zip yarr.exe
|
||||
mv linux/yarr . && zip yarr-linux.zip yarr
|
||||
- name: Upload MacOS
|
||||
uses: actions/upload-release-asset@v1
|
||||
mv macos yarr.app && zip -r yarr-${GITHUB_REF_NAME}-macos64.zip yarr.app
|
||||
( cd windows && zip ../yarr-${GITHUB_REF_NAME}-windows64.zip yarr.exe )
|
||||
( cd linux && zip ../yarr-${GITHUB_REF_NAME}-linux64.zip yarr )
|
||||
( cd linux_arm && zip ../yarr-${GITHUB_REF_NAME}-linux_arm.zip yarr )
|
||||
( cd linux_arm64 && zip ../yarr-${GITHUB_REF_NAME}-linux_arm64.zip yarr )
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./yarr-macos.zip
|
||||
asset_name: yarr-${{ github.ref }}-macos64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload Windows
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./yarr-windows.zip
|
||||
asset_name: yarr-${{ github.ref }}-windows64.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload Linux
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ./yarr-linux.zip
|
||||
asset_name: yarr-${{ github.ref }}-linux64.zip
|
||||
asset_content_type: application/zip
|
||||
draft: true
|
||||
prerelease: true
|
||||
files: |
|
||||
yarr-${{ github.ref_name }}-macos64.zip
|
||||
yarr-${{ github.ref_name }}-windows64.zip
|
||||
yarr-${{ github.ref_name }}-linux64.zip
|
||||
yarr-${{ github.ref_name }}-linux_arm.zip
|
||||
yarr-${{ github.ref_name }}-linux_arm64.zip
|
||||
|
||||
19
.github/workflows/test.yml
vendored
Normal file
19
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Test
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '^1.18'
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
/_output
|
||||
/yarr
|
||||
*.db
|
||||
*.db-shm
|
||||
*.db-wal
|
||||
*.syso
|
||||
versioninfo.rc
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/nkanaev/yarr/src/platform"
|
||||
"github.com/nkanaev/yarr/src/server"
|
||||
"github.com/nkanaev/yarr/src/storage"
|
||||
"github.com/nkanaev/yarr/src/worker"
|
||||
)
|
||||
|
||||
var Version string = "0.0"
|
||||
@@ -89,12 +90,12 @@ func main() {
|
||||
log.SetOutput(os.Stdout)
|
||||
}
|
||||
|
||||
configPath, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to get config dir: ", err)
|
||||
}
|
||||
|
||||
if db == "" {
|
||||
configPath, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to get config dir: ", err)
|
||||
}
|
||||
|
||||
storagePath := filepath.Join(configPath, "yarr")
|
||||
if err := os.MkdirAll(storagePath, 0755); err != nil {
|
||||
log.Fatal("Failed to create app config dir: ", err)
|
||||
@@ -105,6 +106,7 @@ func main() {
|
||||
log.Printf("using db file %s", db)
|
||||
|
||||
var username, password string
|
||||
var err error
|
||||
if authfile != "" {
|
||||
f, err := os.Open(authfile)
|
||||
if err != nil {
|
||||
@@ -131,6 +133,7 @@ func main() {
|
||||
log.Fatal("Failed to initialise database: ", err)
|
||||
}
|
||||
|
||||
worker.SetVersion(Version)
|
||||
srv := server.NewServer(store, addr)
|
||||
|
||||
if basepath != "" {
|
||||
@@ -18,7 +18,7 @@ Then run one of the corresponding commands:
|
||||
make serve # starts a server at http://localhost:7070
|
||||
|
||||
# ... or build a docker image
|
||||
docker build -t yarr .
|
||||
docker build -t yarr -f etc/dockerfile .
|
||||
|
||||
## ARM compilation
|
||||
|
||||
@@ -26,7 +26,7 @@ The instructions below are to cross-compile *yarr* to `Linux/ARM*`.
|
||||
|
||||
Build:
|
||||
|
||||
docker build -t yarr.arm -f dockerfile.arm .
|
||||
docker build -t yarr.arm -f etc/dockerfile.arm .
|
||||
|
||||
Test:
|
||||
|
||||
@@ -1,4 +1,24 @@
|
||||
# upcoming
|
||||
# upcoming
|
||||
|
||||
- (new) Fever API support (thanks to @icefed)
|
||||
- (new) editable feed link (thanks to @adaszko)
|
||||
- (new) switch to feed by clicking the title in the article page (thanks to @tarasglek for suggestion)
|
||||
- (new) support multiple media links
|
||||
- (fix) duplicate articles caused by the same feed addition (thanks to @adaszko)
|
||||
- (fix) relative article links (thanks to @adazsko for the report)
|
||||
- (fix) atom article links stored in id element (thanks to @adazsko for the report)
|
||||
- (fix) parsing atom feed titles (thanks to @wnh)
|
||||
- (fix) sorting same-day batch articles (thanks to @lamescholar for the report)
|
||||
- (fix) showing login page in the selected theme (thanks to @feddiriko for the report)
|
||||
- (fix) parsing atom feeds with html elements (thanks to @tillcash & @toBeOfUse for the report, @krkk for the fix)
|
||||
- (fix) parsing feeds with missing guids (thanks to @hoyii for the report)
|
||||
- (fix) sending actual client version to servers (thanks to @aidanholm)
|
||||
- (fix) error caused by missing config dir (thanks to @timster)
|
||||
- (etc) load external images with no-referrer policy (thanks to @tillcash for the report)
|
||||
- (etc) open external links with no-referrer policy (thanks to @donovanglover)
|
||||
- (etc) show article content in the list if title is missing (thanks to @asimpson for suggestion)
|
||||
|
||||
# v2.4 (2023-08-15)
|
||||
|
||||
- (new) ARM build support (thanks to @tillcash & @fenuks)
|
||||
- (new) auth configuration via param or env variable (thanks to @pierreprinetti)
|
||||
|
||||
19
doc/fever.md
Normal file
19
doc/fever.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Fever API support
|
||||
|
||||
Fever API is a kind of RSS HTTP API interface, because the Fever API definition is not very clear, so the implementation of Fever server and Client may have some compatibility problems.
|
||||
|
||||
The Fever API implemented by Yarr is based on the Fever API spec: https://github.com/DigitalDJ/tinytinyrss-fever-plugin/blob/master/fever-api.md.
|
||||
|
||||
Here are some Apps that have been tested to work with yarr. Feel free to test other Clients/Apps and update the list here.
|
||||
|
||||
> Different apps support different URL/Address formats. Please note whether the URL entered has `http://` scheme and `/` suffix.
|
||||
|
||||
| App | Platforms | Config Server URL |
|
||||
|:------------------------------------------------------------------------- | ---------------- |:--------------------------------------------------- |
|
||||
| [Reeder](https://reederapp.com/) | MacOS<br>iOS | 127.0.0.1:7070/fever<br>http://127.0.0.1:7070/fever |
|
||||
| [ReadKit](https://readkit.app/) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
|
||||
| [Fluent Reader](https://github.com/yang991178/fluent-reader) | MacOS<br>Windows | http://127.0.0.1:7070/fever/ |
|
||||
| [Unread](https://apps.apple.com/us/app/unread-an-rss-reader/id1363637349) | iOS | http://127.0.0.1:7070/fever |
|
||||
| [Fiery Feeds](https://voidstern.net/fiery-feeds) | MacOS<br>iOS | http://127.0.0.1:7070/fever |
|
||||
|
||||
If you are having trouble using Fever, please open an issue and @icefed, thanks.
|
||||
68
doc/samples.yml
Normal file
68
doc/samples.yml
Normal file
@@ -0,0 +1,68 @@
|
||||
- site: https://vimeo.com/channels/staffpicks/videos
|
||||
feed: https://vimeo.com/channels/staffpicks/videos/rss
|
||||
tags: [vimeo, image]
|
||||
|
||||
- site: https://www.youtube.com/@everyframeapainting/videos
|
||||
feed: https://www.youtube.com/feeds/videos.xml?channel_id=UCjFqcJQXGZ6T6sxyFB-5i6A"
|
||||
tags: [youtube, image]
|
||||
|
||||
- site: https://iwdrm.tumblr.com/
|
||||
feed: https://iwdrm.tumblr.com/rss
|
||||
tags: [tumblr, image]
|
||||
|
||||
- site: https://falseknees.tumblr.com/
|
||||
feed: https://falseknees.tumblr.com/rss
|
||||
tags: [tumblr, image]
|
||||
|
||||
- site: https://accidentallyquadratic.tumblr.com/
|
||||
feed: https://accidentallyquadratic.tumblr.com/rss
|
||||
info: text blog with code sections
|
||||
tags: [tumblr, text, code]
|
||||
|
||||
- site: https://www.flickr.com/photos/maratsafin/
|
||||
feed: https://www.flickr.com/services/feeds/photos_public.gne?id=59021497@N07&lang=en-us&format=atom
|
||||
tags: [flickr, image]
|
||||
|
||||
- site: https://www.reddit.com/r/comics
|
||||
feed: https://www.reddit.com/r/comics.rss
|
||||
tags: [reddit, image]
|
||||
|
||||
- site: https://www.reddit.com/r/AITAH
|
||||
feed: https://www.reddit.com/r/AITAH.rss
|
||||
tags: [reddit, text]
|
||||
|
||||
- site: https://idothei.wordpress.com/
|
||||
feed: https://idothei.wordpress.com/feed/
|
||||
tags: [wordpress, text]
|
||||
|
||||
- site: https://www.vidarholen.net/contents/blog/
|
||||
feed: https://www.vidarholen.net/contents/blog/?feed=rss2
|
||||
tags: [wordpress, text]
|
||||
|
||||
- site: https://blog.posthaven.com/
|
||||
feed: https://blog.posthaven.com/posts.atom
|
||||
tags: [posthaven, text]
|
||||
|
||||
- site: https://medium.com/@dailynewsletter
|
||||
feed: https://medium.com/feed/@dailynewsletter
|
||||
tags: [medium, text]
|
||||
|
||||
- site: https://thereveal.substack.com/
|
||||
feed: https://thereveal.substack.com/feed
|
||||
tags: [substack, text]
|
||||
|
||||
- site: https://tema.livejournal.com/
|
||||
feed: https://tema.livejournal.com/data/rss
|
||||
tags: [livejournal, text]
|
||||
|
||||
- site: https://mametter.hatenablog.com/
|
||||
feed: https://mametter.hatenablog.com/feed
|
||||
tags: [hatena, text]
|
||||
|
||||
- site: https://juliepowell.blogspot.com/
|
||||
feed: https://juliepowell.blogspot.com/feeds/posts/default
|
||||
tags: [blogger, text]
|
||||
|
||||
- site: https://micro.blog/val
|
||||
feed: https://micro.blog/posts/val
|
||||
tags: [json, microblog]
|
||||
12
dockerfile
12
dockerfile
@@ -1,12 +0,0 @@
|
||||
FROM golang:alpine AS build
|
||||
RUN apk add build-base git
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN make build_linux
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add --no-cache ca-certificates && \
|
||||
update-ca-certificates
|
||||
COPY --from=build /src/_output/linux/yarr /usr/local/bin/yarr
|
||||
EXPOSE 7070
|
||||
CMD ["/usr/local/bin/yarr", "-addr", "0.0.0.0:7070", "-db", "/data/yarr.db"]
|
||||
14
etc/dockerfile
Normal file
14
etc/dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM golang:alpine3.18 AS build
|
||||
RUN apk add build-base git
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
RUN --mount=type=cache,target=/root/.cache/go-build --mount=type=cache,target=/root/go/pkg \
|
||||
make build_linux
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk add --no-cache ca-certificates && \
|
||||
update-ca-certificates
|
||||
COPY --from=build /src/_output/linux/yarr /usr/local/bin/yarr
|
||||
EXPOSE 7070
|
||||
ENTRYPOINT ["/usr/local/bin/yarr"]
|
||||
CMD ["-addr", "0.0.0.0:7070", "-db", "/data/yarr.db"]
|
||||
@@ -28,17 +28,17 @@ RUN env \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=linux GOARCH=arm64 \
|
||||
go build \
|
||||
-tags "sqlite_foreign_keys release linux" \
|
||||
-tags "sqlite_foreign_keys linux" \
|
||||
-ldflags="-s -w" \
|
||||
-o /root/out/yarr.arm64 src/main.go
|
||||
-o /root/out/yarr.arm64 ./cmd/yarr
|
||||
|
||||
RUN env \
|
||||
CC=arm-linux-gnueabihf-gcc \
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=linux GOARCH=arm GOARM=7 \
|
||||
go build \
|
||||
-tags "sqlite_foreign_keys release linux" \
|
||||
-tags "sqlite_foreign_keys linux" \
|
||||
-ldflags="-s -w" \
|
||||
-o /root/out/yarr.arm7 src/main.go
|
||||
-o /root/out/yarr.arm7 ./cmd/yarr
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -1,5 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [[ ! -d "$HOME/.local/share/applications" ]]; then
|
||||
mkdir -p "$HOME/.local/share/applications"
|
||||
fi
|
||||
|
||||
cat >"$HOME/.local/share/applications/yarr.desktop" <<END
|
||||
[Desktop Entry]
|
||||
Name=yarr
|
||||
@@ -9,6 +13,10 @@ Type=Application
|
||||
Categories=Internet;
|
||||
END
|
||||
|
||||
if [[ ! -d "$HOME/.local/share/icons" ]]; then
|
||||
mkdir -p "$HOME/.local/share/icons"
|
||||
fi
|
||||
|
||||
cat >"$HOME/.local/share/icons/yarr.svg" <<END
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-anchor-favicon">
|
||||
|
||||
BIN
etc/promo.png
BIN
etc/promo.png
Binary file not shown.
|
Before Width: | Height: | Size: 223 KiB After Width: | Height: | Size: 173 KiB |
8
go.mod
8
go.mod
@@ -1,11 +1,11 @@
|
||||
module github.com/nkanaev/yarr
|
||||
|
||||
go 1.17
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/mattn/go-sqlite3 v1.14.7
|
||||
golang.org/x/net v0.8.0
|
||||
golang.org/x/sys v0.6.0
|
||||
golang.org/x/net v0.33.0
|
||||
golang.org/x/sys v0.28.0
|
||||
)
|
||||
|
||||
require golang.org/x/text v0.8.0 // indirect
|
||||
require golang.org/x/text v0.21.0 // indirect
|
||||
|
||||
45
go.sum
45
go.sum
@@ -1,39 +1,70 @@
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
25
makefile
25
makefile
@@ -1,33 +1,34 @@
|
||||
VERSION=2.3
|
||||
VERSION=2.4
|
||||
GITHASH=$(shell git rev-parse --short=8 HEAD)
|
||||
|
||||
CGO_ENABLED=1
|
||||
GO_TAGS = sqlite_foreign_keys sqlite_json
|
||||
GO_LDFLAGS = -s -w -X 'main.Version=$(VERSION)' -X 'main.GitHash=$(GITHASH)'
|
||||
|
||||
GO_LDFLAGS = -s -w
|
||||
GO_LDFLAGS := $(GO_LDFLAGS) -X 'main.Version=$(VERSION)' -X 'main.GitHash=$(GITHASH)'
|
||||
export GOARCH ?= amd64
|
||||
export CGO_ENABLED = 1
|
||||
|
||||
build_default:
|
||||
mkdir -p _output
|
||||
go build -tags "sqlite_foreign_keys release" -ldflags="$(GO_LDFLAGS)" -o _output/yarr src/main.go
|
||||
go build -tags "$(GO_TAGS)" -ldflags="$(GO_LDFLAGS)" -o _output/yarr ./cmd/yarr
|
||||
|
||||
build_macos:
|
||||
mkdir -p _output/macos
|
||||
GOOS=darwin GOARCH=amd64 go build -tags "sqlite_foreign_keys release macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr src/main.go
|
||||
GOOS=darwin go build -tags "$(GO_TAGS) macos" -ldflags="$(GO_LDFLAGS)" -o _output/macos/yarr ./cmd/yarr
|
||||
cp src/platform/icon.png _output/macos/icon.png
|
||||
go run bin/package_macos.go -outdir _output/macos -version "$(VERSION)"
|
||||
go run ./cmd/package_macos -outdir _output/macos -version "$(VERSION)"
|
||||
|
||||
build_linux:
|
||||
mkdir -p _output/linux
|
||||
GOOS=linux GOARCH=amd64 go build -tags "sqlite_foreign_keys release linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr src/main.go
|
||||
GOOS=linux go build -tags "$(GO_TAGS) linux" -ldflags="$(GO_LDFLAGS)" -o _output/linux/yarr ./cmd/yarr
|
||||
|
||||
build_windows:
|
||||
mkdir -p _output/windows
|
||||
go run bin/generate_versioninfo.go -version "$(VERSION)" -outfile src/platform/versioninfo.rc
|
||||
go run ./cmd/generate_versioninfo -version "$(VERSION)" -outfile src/platform/versioninfo.rc
|
||||
windres -i src/platform/versioninfo.rc -O coff -o src/platform/versioninfo.syso
|
||||
GOOS=windows GOARCH=amd64 go build -tags "sqlite_foreign_keys release windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe src/main.go
|
||||
GOOS=windows go build -tags "$(GO_TAGS) windows" -ldflags="$(GO_LDFLAGS) -H windowsgui" -o _output/windows/yarr.exe ./cmd/yarr
|
||||
|
||||
serve:
|
||||
go run -tags "sqlite_foreign_keys" src/main.go -db local.db
|
||||
go run -tags "$(GO_TAGS)" ./cmd/yarr -db local.db
|
||||
|
||||
test:
|
||||
cd src && go test -tags "sqlite_foreign_keys release" ./...
|
||||
go test -tags "$(GO_TAGS)" ./...
|
||||
|
||||
34
readme.md
34
readme.md
@@ -3,32 +3,36 @@
|
||||
**yarr** (yet another rss reader) is a web-based feed aggregator which can be used both
|
||||
as a desktop application and a personal self-hosted server.
|
||||
|
||||
It is written in Go with the frontend in Vue.js. The storage is backed by SQLite.
|
||||
The app is a single binary with an embedded database (SQLite).
|
||||
|
||||

|
||||
|
||||
## usage
|
||||
|
||||
The latest prebuilt binaries for Linux/MacOS/Windows are available
|
||||
[here](https://github.com/nkanaev/yarr/releases/latest).
|
||||
The latest prebuilt binaries for Linux/MacOS/Windows AMD64 are available
|
||||
[here](https://github.com/nkanaev/yarr/releases/latest). Installation instructions:
|
||||
|
||||
### macos
|
||||
* MacOS
|
||||
|
||||
Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder, [open the app][macos-open], click the anchor menu bar icon, select "Open".
|
||||
Download `yarr-*-macos64.zip`, unzip it, place `yarr.app` in `/Applications` folder, [open the app][macos-open], click the anchor menu bar icon, select "Open".
|
||||
|
||||
* Windows
|
||||
|
||||
Download `yarr-*-windows64.zip`, unzip it, open `yarr.exe`, click the anchor system tray icon, select "Open".
|
||||
|
||||
* Linux
|
||||
|
||||
Download `yarr-*-linux64.zip`, unzip it, place `yarr` in `$HOME/.local/bin`
|
||||
and run [the script](etc/install-linux.sh).
|
||||
|
||||
[macos-open]: https://support.apple.com/en-gb/guide/mac-help/mh40616/mac
|
||||
|
||||
### windows
|
||||
|
||||
Download `yarr-*-windows64.zip`, unzip it, open `yarr.exe`, click the anchor system tray icon, select "Open".
|
||||
|
||||
### linux
|
||||
|
||||
Download `yarr-*-linux64.zip`, unzip it, place `yarr` in `$HOME/.local/bin`
|
||||
and run [the script](etc/install-linux.sh).
|
||||
|
||||
For self-hosting, see `yarr -h` for auth, tls & server configuration flags.
|
||||
For building from source code, see [build.md](build.md)
|
||||
|
||||
See more:
|
||||
|
||||
* [Building from source code](doc/build.md)
|
||||
* [Fever API support](doc/fever.md)
|
||||
|
||||
## credits
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//go:build release
|
||||
// +build release
|
||||
|
||||
package assets
|
||||
|
||||
import "embed"
|
||||
|
||||
@@ -25,18 +25,21 @@
|
||||
<div class="flex-grow-1"></div>
|
||||
<button class="toolbar-item"
|
||||
:class="{active: filterSelected == 'unread'}"
|
||||
:aria-pressed="filterSelected == 'unread'"
|
||||
title="Unread"
|
||||
@click="filterSelected = 'unread'">
|
||||
<span class="icon">{% inline "circle-full.svg" %}</span>
|
||||
</button>
|
||||
<button class="toolbar-item"
|
||||
:class="{active: filterSelected == 'starred'}"
|
||||
:aria-pressed="filterSelected == 'starred'"
|
||||
title="Starred"
|
||||
@click="filterSelected = 'starred'">
|
||||
<span class="icon">{% inline "star-full.svg" %}</span>
|
||||
</button>
|
||||
<button class="toolbar-item"
|
||||
:class="{active: filterSelected == ''}"
|
||||
:aria-pressed="filterSelected == ''"
|
||||
title="All"
|
||||
@click="filterSelected = ''">
|
||||
<span class="icon">{% inline "assorted.svg" %}</span>
|
||||
@@ -59,10 +62,12 @@
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<header class="dropdown-header">Theme</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">Theme</header>
|
||||
<div class="row text-center m-0">
|
||||
<button class="btn btn-link col-4 px-0 rounded-0"
|
||||
:class="'theme-'+t"
|
||||
:aria-label="t"
|
||||
:aria-pressed="theme.name == t"
|
||||
@click.stop="theme.name = t"
|
||||
v-for="t in ['light', 'sepia', 'night']">
|
||||
<span class="icon" v-if="theme.name == t">{% inline "check.svg" %}</span>
|
||||
@@ -71,25 +76,25 @@
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<header class="dropdown-header">Auto Refresh</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">Auto Refresh</header>
|
||||
<div class="row text-center m-0">
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: !refreshRate}" @click.stop="refreshRate = 0">0</button>
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 10}" @click.stop="refreshRate = 10">10m</button>
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 30}" @click.stop="refreshRate = 30">30m</button>
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 60}" @click.stop="refreshRate = 60">1h</button>
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 120}" @click.stop="refreshRate = 120">2h</button>
|
||||
<button class="dropdown-item col-4 px-0" :class="{active: refreshRate == 240}" @click.stop="refreshRate = 240">4h</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="!refreshRate" :class="{active: !refreshRate}" @click.stop="refreshRate = 0">0</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 10" :class="{active: refreshRate == 10}" @click.stop="refreshRate = 10">10m</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 30" :class="{active: refreshRate == 30}" @click.stop="refreshRate = 30">30m</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 60" :class="{active: refreshRate == 60}" @click.stop="refreshRate = 60">1h</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 120" :class="{active: refreshRate == 120}" @click.stop="refreshRate = 120">2h</button>
|
||||
<button class="dropdown-item col-4 px-0" :aria-pressed="refreshRate == 240" :class="{active: refreshRate == 240}" @click.stop="refreshRate = 240">4h</button>
|
||||
</div>
|
||||
|
||||
<div class="dropdown-divider"></div>
|
||||
|
||||
<header class="dropdown-header">Show first</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">Show first</header>
|
||||
<div class="d-flex text-center">
|
||||
<button class="dropdown-item px-0" :class="{active: itemSortNewestFirst}" @click.stop="itemSortNewestFirst=true">New</button>
|
||||
<button class="dropdown-item px-0" :class="{active: !itemSortNewestFirst}" @click.stop="itemSortNewestFirst=false">Old</button>
|
||||
<button class="dropdown-item px-0" :aria-pressed="itemSortNewestFirst" :class="{active: itemSortNewestFirst}" @click.stop="itemSortNewestFirst=true">New</button>
|
||||
<button class="dropdown-item px-0" :aria-pressed="!itemSortNewestFirst" :class="{active: !itemSortNewestFirst}" @click.stop="itemSortNewestFirst=false">Old</button>
|
||||
</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<header class="dropdown-header">Subscriptions</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">Subscriptions</header>
|
||||
<form id="opml-import-form" enctype="multipart/form-data" tabindex="-1">
|
||||
<input type="file"
|
||||
id="opml-import"
|
||||
@@ -133,7 +138,7 @@
|
||||
:class="{'d-none': filterSelected
|
||||
&& !(current.folder.id == folder.id || current.feed.folder_id == folder.id)
|
||||
&& !filteredFolderStats[folder.id]
|
||||
&& (!itemSelectedDetails || feedsById[itemSelectedDetails.feed_id].folder_id != folder.id)}">
|
||||
&& (!itemSelectedDetails || (feedsById[itemSelectedDetails.feed_id] || {}).folder_id != folder.id)}">
|
||||
<input type="radio" name="feed" :value="'folder:'+folder.id" v-model="feedSelected" v-if="folder.id">
|
||||
<div class="selectgroup-label d-flex align-items-center w-100" v-if="folder.id">
|
||||
<span class="icon mr-2"
|
||||
@@ -206,12 +211,12 @@
|
||||
<template v-slot:button>
|
||||
<span class="icon">{% inline "more-horizontal.svg" %}</span>
|
||||
</template>
|
||||
<header class="dropdown-header">{{ current.feed.title }}</header>
|
||||
<a class="dropdown-item" :href="current.feed.link" target="_blank" v-if="current.feed.link">
|
||||
<header class="dropdown-header" role="heading" aria-level="2">{{ current.feed.title }}</header>
|
||||
<a class="dropdown-item" :href="current.feed.link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" v-if="current.feed.link">
|
||||
<span class="icon mr-1">{% inline "globe.svg" %}</span>
|
||||
Website
|
||||
</a>
|
||||
<a class="dropdown-item" :href="current.feed.feed_link" target="_blank" v-if="current.feed.feed_link">
|
||||
<a class="dropdown-item" :href="current.feed.feed_link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" v-if="current.feed.feed_link">
|
||||
<span class="icon mr-1">{% inline "rss.svg" %}</span>
|
||||
Feed Link
|
||||
</a>
|
||||
@@ -220,8 +225,12 @@
|
||||
<span class="icon mr-1">{% inline "edit.svg" %}</span>
|
||||
Rename
|
||||
</button>
|
||||
<button class="dropdown-item" @click="updateFeedLink(current.feed)" v-if="current.feed.feed_link">
|
||||
<span class="icon mr-1">{% inline "edit.svg" %}</span>
|
||||
Change Link
|
||||
</button>
|
||||
<div class="dropdown-divider"></div>
|
||||
<header class="dropdown-header">Move to...</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">Move to...</header>
|
||||
<button class="dropdown-item"
|
||||
v-if="folder.id != current.feed.folder_id"
|
||||
v-for="folder in folders"
|
||||
@@ -251,7 +260,7 @@
|
||||
<template v-slot:button>
|
||||
<span class="icon">{% inline "more-horizontal.svg" %}</span>
|
||||
</template>
|
||||
<header class="dropdown-header">{{ current.folder.title }}</header>
|
||||
<header class="dropdown-header" role="heading" aria-level="2">{{ current.folder.title }}</header>
|
||||
<button class="dropdown-item" @click="renameFolder(current.folder)">
|
||||
<span class="icon mr-1">{% inline "edit.svg" %}</span>
|
||||
Rename
|
||||
@@ -274,7 +283,7 @@
|
||||
<span class="icon icon-small mr-1" v-if="item.status=='starred'">{% inline "star-full.svg" %}</span>
|
||||
</transition>
|
||||
<small class="flex-fill text-truncate mr-1">
|
||||
{{ feedsById[item.feed_id].title }}
|
||||
{{ (feedsById[item.feed_id] || {}).title }}
|
||||
</small>
|
||||
<small class="flex-shrink-0"><relative-time v-bind:title="formatDate(item.date)" :val="item.date"/></small>
|
||||
</div>
|
||||
@@ -322,10 +331,16 @@
|
||||
title="Read Here">
|
||||
<span class="icon" :class="{'icon-loading': loading.readability}">{% inline "book-open.svg" %}</span>
|
||||
</button>
|
||||
<a class="toolbar-item" :href="itemSelectedDetails.link" target="_blank" title="Open Link">
|
||||
<a class="toolbar-item" :href="itemSelectedDetails.link" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer" title="Open Link">
|
||||
<span class="icon">{% inline "external-link.svg" %}</span>
|
||||
</a>
|
||||
<div class="flex-grow-1"></div>
|
||||
<button class="toolbar-item" @click="navigateToItem(-1)" title="Previous Article" :disabled="itemSelected == items[0].id">
|
||||
<span class="icon">{% inline "chevron-left.svg" %}</span>
|
||||
</button>
|
||||
<button class="toolbar-item" @click="navigateToItem(+1)" title="Next Article" :disabled="itemSelected == items[items.length - 1].id">
|
||||
<span class="icon">{% inline "chevron-right.svg" %}</span>
|
||||
</button>
|
||||
<button class="toolbar-item" @click="itemSelected=null" title="Close Article">
|
||||
<span class="icon">{% inline "x.svg" %}</span>
|
||||
</button>
|
||||
@@ -338,13 +353,23 @@
|
||||
<div class="content-wrapper">
|
||||
<h1><b>{{ itemSelectedDetails.title || 'untitled' }}</b></h1>
|
||||
<div class="text-muted">
|
||||
<div>{{ feedsById[itemSelectedDetails.feed_id].title }}</div>
|
||||
<div>
|
||||
<span class="cursor-pointer" @click="feedSelected = 'feed:'+(feedsById[itemSelectedDetails.feed_id] || {}).id">
|
||||
{{ (feedsById[itemSelectedDetails.feed_id] || {}).title }}
|
||||
</span>
|
||||
</div>
|
||||
<time>{{ formatDate(itemSelectedDetails.date) }}</time>
|
||||
</div>
|
||||
<hr>
|
||||
<div v-if="!itemSelectedReadability">
|
||||
<img :src="itemSelectedDetails.image" v-if="itemSelectedDetails.image" class="mb-3">
|
||||
<audio class="w-100" controls v-if="itemSelectedDetails.podcast_url" :src="itemSelectedDetails.podcast_url"></audio>
|
||||
<div v-if="contentImages.length">
|
||||
<figure v-for="media in contentImages">
|
||||
<img :src="media.url" loading="lazy">
|
||||
<figcaption v-if="media.description" v-html="media.description"></figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
<audio class="w-100" controls v-for="media in contentAudios" :src="media.url"></audio>
|
||||
<video class="w-100" controls v-for="media in contentVideos" :src="media.url"></video>
|
||||
</div>
|
||||
<div v-html="itemSelectedContent"></div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,26 @@
|
||||
|
||||
var TITLE = document.title
|
||||
|
||||
function scrollto(target, scroll) {
|
||||
var padding = 10
|
||||
var targetRect = target.getBoundingClientRect()
|
||||
var scrollRect = scroll.getBoundingClientRect()
|
||||
|
||||
// target
|
||||
var relativeOffset = targetRect.y - scrollRect.y
|
||||
var absoluteOffset = relativeOffset + scroll.scrollTop
|
||||
|
||||
if (padding <= relativeOffset && relativeOffset + targetRect.height <= scrollRect.height - padding) return
|
||||
|
||||
var newPos = scroll.scrollTop
|
||||
if (relativeOffset < padding) {
|
||||
newPos = absoluteOffset - padding
|
||||
} else {
|
||||
newPos = absoluteOffset - scrollRect.height + targetRect.height + padding
|
||||
}
|
||||
scroll.scrollTop = Math.round(newPos)
|
||||
}
|
||||
|
||||
var debounce = function(callback, wait) {
|
||||
var timeout
|
||||
return function() {
|
||||
@@ -278,6 +298,18 @@ var vm = new Vue({
|
||||
|
||||
return this.itemSelectedDetails.content || ''
|
||||
},
|
||||
contentImages: function() {
|
||||
if (!this.itemSelectedDetails) return []
|
||||
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'image')
|
||||
},
|
||||
contentAudios: function() {
|
||||
if (!this.itemSelectedDetails) return []
|
||||
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'audio')
|
||||
},
|
||||
contentVideos: function() {
|
||||
if (!this.itemSelectedDetails) return []
|
||||
return (this.itemSelectedDetails.media_links || []).filter(l => l.type === 'video')
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'theme': {
|
||||
@@ -407,9 +439,10 @@ var vm = new Vue({
|
||||
vm.feeds = values[1]
|
||||
})
|
||||
},
|
||||
refreshItems: function(loadMore) {
|
||||
refreshItems: function(loadMore = false) {
|
||||
if (this.feedSelected === null) {
|
||||
vm.items = []
|
||||
vm.itemsHasMore = false
|
||||
return
|
||||
}
|
||||
|
||||
@@ -419,7 +452,7 @@ var vm = new Vue({
|
||||
}
|
||||
|
||||
this.loading.items = true
|
||||
api.items.list(query).then(function(data) {
|
||||
return api.items.list(query).then(function(data) {
|
||||
if (loadMore) {
|
||||
vm.items = vm.items.concat(data.list)
|
||||
} else {
|
||||
@@ -442,13 +475,17 @@ var vm = new Vue({
|
||||
var scale = (parseFloat(getComputedStyle(document.documentElement).fontSize) || 16) / 16
|
||||
|
||||
var el = this.$refs.itemlist
|
||||
|
||||
if (el.scrollHeight === 0) return false // element is invisible (responsive design)
|
||||
|
||||
var closeToBottom = (el.scrollHeight - el.scrollTop - el.offsetHeight) < bottomSpace * scale
|
||||
return closeToBottom
|
||||
},
|
||||
loadMoreItems: function(event, el) {
|
||||
if (!this.itemsHasMore) return
|
||||
if (this.loading.items) return
|
||||
if (this.itemListCloseToBottom()) this.refreshItems(true)
|
||||
if (this.itemListCloseToBottom()) return this.refreshItems(true)
|
||||
if (this.itemSelected && this.itemSelected === this.items[this.items.length - 1].id) return this.refreshItems(true)
|
||||
},
|
||||
markItemsRead: function() {
|
||||
var query = this.getItemsQuery()
|
||||
@@ -516,15 +553,20 @@ var vm = new Vue({
|
||||
deleteFolder: function(folder) {
|
||||
if (confirm('Are you sure you want to delete ' + folder.title + '?')) {
|
||||
api.folders.delete(folder.id).then(function() {
|
||||
if (vm.feedSelected === 'folder:'+folder.id) {
|
||||
vm.items = []
|
||||
vm.feedSelected = ''
|
||||
}
|
||||
vm.feedSelected = null
|
||||
vm.refreshStats()
|
||||
vm.refreshFeeds()
|
||||
})
|
||||
}
|
||||
},
|
||||
updateFeedLink: function(feed) {
|
||||
var newLink = prompt('Enter feed link', feed.feed_link)
|
||||
if (newLink) {
|
||||
api.feeds.update(feed.id, {feed_link: newLink}).then(function() {
|
||||
feed.feed_link = newLink
|
||||
})
|
||||
}
|
||||
},
|
||||
renameFeed: function(feed) {
|
||||
var newTitle = prompt('Enter new title', feed.title)
|
||||
if (newTitle) {
|
||||
@@ -536,12 +578,7 @@ var vm = new Vue({
|
||||
deleteFeed: function(feed) {
|
||||
if (confirm('Are you sure you want to delete ' + feed.title + '?')) {
|
||||
api.feeds.delete(feed.id).then(function() {
|
||||
// unselect feed to prevent reading properties of null in template
|
||||
var isSelected = !vm.feedSelected
|
||||
|| (vm.feedSelected === 'feed:'+feed.id
|
||||
|| (feed.folder_id && vm.feedSelected === 'folder:'+feed.folder_id));
|
||||
if (isSelected) vm.feedSelected = null
|
||||
|
||||
vm.feedSelected = null
|
||||
vm.refreshStats()
|
||||
vm.refreshFeeds()
|
||||
})
|
||||
@@ -682,6 +719,65 @@ var vm = new Vue({
|
||||
this.filteredFolderStats = statsFolders
|
||||
this.filteredTotalStats = statsTotal
|
||||
},
|
||||
// navigation helper, navigate relative to selected item
|
||||
navigateToItem: function(relativePosition) {
|
||||
let vm = this
|
||||
if (vm.itemSelected == null) {
|
||||
// if no item is selected, select first
|
||||
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
|
||||
return
|
||||
}
|
||||
|
||||
var itemPosition = vm.items.findIndex(function(x) { return x.id === vm.itemSelected })
|
||||
if (itemPosition === -1) {
|
||||
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
|
||||
return
|
||||
}
|
||||
|
||||
var newPosition = itemPosition + relativePosition
|
||||
if (newPosition < 0 || newPosition >= vm.items.length) return
|
||||
|
||||
vm.itemSelected = vm.items[newPosition].id
|
||||
|
||||
vm.$nextTick(function() {
|
||||
var scroll = document.querySelector('#item-list-scroll')
|
||||
|
||||
var handle = scroll.querySelector('input[type=radio]:checked')
|
||||
var target = handle && handle.parentElement
|
||||
|
||||
if (target && scroll) scrollto(target, scroll)
|
||||
|
||||
vm.loadMoreItems()
|
||||
})
|
||||
},
|
||||
// navigation helper, navigate relative to selected feed
|
||||
navigateToFeed: function(relativePosition) {
|
||||
let vm = this
|
||||
var navigationList = Array.from(document.querySelectorAll('#col-feed-list input[name=feed]'))
|
||||
.filter(function(r) { return r.offsetParent !== null && r.value !== 'folder:null' })
|
||||
.map(function(r) { return r.value })
|
||||
|
||||
var currentFeedPosition = navigationList.indexOf(vm.feedSelected)
|
||||
|
||||
if (currentFeedPosition == -1) {
|
||||
vm.feedSelected = ''
|
||||
return
|
||||
}
|
||||
|
||||
var newPosition = currentFeedPosition+relativePosition
|
||||
if (newPosition < 0 || newPosition >= navigationList.length) return
|
||||
|
||||
vm.feedSelected = navigationList[newPosition]
|
||||
|
||||
vm.$nextTick(function() {
|
||||
var scroll = document.querySelector('#feed-list-scroll')
|
||||
|
||||
var handle = scroll.querySelector('input[type=radio]:checked')
|
||||
var target = handle && handle.parentElement
|
||||
|
||||
if (target && scroll) scrollto(target, scroll)
|
||||
})
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,79 +1,4 @@
|
||||
function scrollto(target, scroll) {
|
||||
var padding = 10
|
||||
var targetRect = target.getBoundingClientRect()
|
||||
var scrollRect = scroll.getBoundingClientRect()
|
||||
|
||||
// target
|
||||
var relativeOffset = targetRect.y - scrollRect.y
|
||||
var absoluteOffset = relativeOffset + scroll.scrollTop
|
||||
|
||||
if (padding <= relativeOffset && relativeOffset + targetRect.height <= scrollRect.height - padding) return
|
||||
|
||||
var newPos = scroll.scrollTop
|
||||
if (relativeOffset < padding) {
|
||||
newPos = absoluteOffset - padding
|
||||
} else {
|
||||
newPos = absoluteOffset - scrollRect.height + targetRect.height + padding
|
||||
}
|
||||
scroll.scrollTop = Math.round(newPos)
|
||||
}
|
||||
|
||||
var helperFunctions = {
|
||||
// navigation helper, navigate relative to selected item
|
||||
navigateToItem: function(relativePosition) {
|
||||
if (vm.itemSelected == null) {
|
||||
// if no item is selected, select first
|
||||
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
|
||||
return
|
||||
}
|
||||
|
||||
var itemPosition = vm.items.findIndex(function(x) { return x.id === vm.itemSelected })
|
||||
if (itemPosition === -1) {
|
||||
if (vm.items.length !== 0) vm.itemSelected = vm.items[0].id
|
||||
return
|
||||
}
|
||||
|
||||
var newPosition = itemPosition + relativePosition
|
||||
if (newPosition < 0 || newPosition >= vm.items.length) return
|
||||
|
||||
vm.itemSelected = vm.items[newPosition].id
|
||||
|
||||
vm.$nextTick(function() {
|
||||
var scroll = document.querySelector('#item-list-scroll')
|
||||
|
||||
var handle = scroll.querySelector('input[type=radio]:checked')
|
||||
var target = handle && handle.parentElement
|
||||
|
||||
if (target && scroll) scrollto(target, scroll)
|
||||
})
|
||||
},
|
||||
// navigation helper, navigate relative to selected feed
|
||||
navigateToFeed: function(relativePosition) {
|
||||
var navigationList = Array.from(document.querySelectorAll('#col-feed-list input[name=feed]'))
|
||||
.filter(function(r) { return r.offsetParent !== null && r.value !== 'folder:null' })
|
||||
.map(function(r) { return r.value })
|
||||
|
||||
var currentFeedPosition = navigationList.indexOf(vm.feedSelected)
|
||||
|
||||
if (currentFeedPosition == -1) {
|
||||
vm.feedSelected = ''
|
||||
return
|
||||
}
|
||||
|
||||
var newPosition = currentFeedPosition+relativePosition
|
||||
if (newPosition < 0 || newPosition >= navigationList.length) return
|
||||
|
||||
vm.feedSelected = navigationList[newPosition]
|
||||
|
||||
vm.$nextTick(function() {
|
||||
var scroll = document.querySelector('#feed-list-scroll')
|
||||
|
||||
var handle = scroll.querySelector('input[type=radio]:checked')
|
||||
var target = handle && handle.parentElement
|
||||
|
||||
if (target && scroll) scrollto(target, scroll)
|
||||
})
|
||||
},
|
||||
scrollContent: function(direction) {
|
||||
var padding = 40
|
||||
var scroll = document.querySelector('.content')
|
||||
@@ -92,7 +17,7 @@ var helperFunctions = {
|
||||
var shortcutFunctions = {
|
||||
openItemLink: function() {
|
||||
if (vm.itemSelectedDetails && vm.itemSelectedDetails.link) {
|
||||
window.open(vm.itemSelectedDetails.link, '_blank')
|
||||
window.open(vm.itemSelectedDetails.link, '_blank', 'noopener,noreferrer')
|
||||
}
|
||||
},
|
||||
toggleReadability: function() {
|
||||
@@ -118,16 +43,16 @@ var shortcutFunctions = {
|
||||
document.getElementById("searchbar").focus()
|
||||
},
|
||||
nextItem(){
|
||||
helperFunctions.navigateToItem(+1)
|
||||
vm.navigateToItem(+1)
|
||||
},
|
||||
previousItem() {
|
||||
helperFunctions.navigateToItem(-1)
|
||||
vm.navigateToItem(-1)
|
||||
},
|
||||
nextFeed(){
|
||||
helperFunctions.navigateToFeed(+1)
|
||||
vm.navigateToFeed(+1)
|
||||
},
|
||||
previousFeed() {
|
||||
helperFunctions.navigateToFeed(-1)
|
||||
vm.navigateToFeed(-1)
|
||||
},
|
||||
scrollForward: function() {
|
||||
helperFunctions.scrollContent(+1)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<body class="theme-{% .settings.theme_name %}">
|
||||
<form action="" method="post">
|
||||
<img src="./static/graphicarts/anchor.svg" alt="">
|
||||
{% if .error %}
|
||||
|
||||
@@ -2,8 +2,11 @@
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
body {
|
||||
html {
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
body {
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package htmlutil
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Any(els []string, el string, match func(string, string) bool) bool {
|
||||
@@ -31,3 +32,7 @@ func URLDomain(val string) string {
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func IsAPossibleLink(val string) bool {
|
||||
return strings.HasPrefix(val, "http://") || strings.HasPrefix(val, "https://")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"golang.org/x/net/html"
|
||||
)
|
||||
@@ -61,3 +62,16 @@ func ExtractText(content string) string {
|
||||
text = whitespaceRegex.ReplaceAllLiteralString(text, " ")
|
||||
return text
|
||||
}
|
||||
|
||||
func TruncateText(input string, size int) string {
|
||||
runes := []rune(input)
|
||||
if len(runes) <= size {
|
||||
return input
|
||||
}
|
||||
for i := size - 1; i > 0; i-- {
|
||||
if unicode.IsSpace(runes[i]) {
|
||||
return string(runes[:i]) + " ..."
|
||||
}
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
@@ -24,3 +24,21 @@ func TestExtractText(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTruncateText(t *testing.T) {
|
||||
input := "Lorem ipsum — классический текст-«рыба»"
|
||||
|
||||
size := 30
|
||||
want := "Lorem ipsum — классический ..."
|
||||
have := TruncateText(input, size)
|
||||
if want != have {
|
||||
t.Errorf("\nsize: %d\nwant: %#v\nhave: %#v", size, want, have)
|
||||
}
|
||||
|
||||
size = 1000
|
||||
want = input
|
||||
have = TruncateText(input, size)
|
||||
if want != have {
|
||||
t.Errorf("\nsize: %d\nwant: %#v\nhave: %#v", size, want, have)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ func getExtraAttributes(tagName string) ([]string, []string) {
|
||||
case "iframe":
|
||||
return []string{"sandbox", "loading"}, []string{`sandbox="allow-scripts allow-same-origin allow-popups"`, `loading="lazy"`}
|
||||
case "img":
|
||||
return []string{"loading"}, []string{`loading="lazy"`}
|
||||
return []string{"loading"}, []string{`loading="lazy"`, `referrerpolicy="no-referrer"`}
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -8,10 +8,11 @@ import "testing"
|
||||
|
||||
func TestValidInput(t *testing.T) {
|
||||
input := `<p>This is a <strong>text</strong> with an image: <img src="http://example.org/" alt="Test" loading="lazy">.</p>`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<p>This is a <strong>text</strong> with an image: <img src="http://example.org/" alt="Test" loading="lazy" referrerpolicy="no-referrer">.</p>`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if input != output {
|
||||
t.Errorf(`Wrong output: "%s" != "%s"`, input, output)
|
||||
if have != want {
|
||||
t.Errorf("Wrong output: \nwant: %#v\nhave: %#v", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,31 +28,31 @@ func TestImgWithTextDataURL(t *testing.T) {
|
||||
|
||||
func TestImgWithDataURL(t *testing.T) {
|
||||
input := `<img src="data:image/gif;base64,test" alt="Example">`
|
||||
expected := `<img src="data:image/gif;base64,test" alt="Example" loading="lazy">`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<img src="data:image/gif;base64,test" alt="Example" loading="lazy" referrerpolicy="no-referrer">`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if output != expected {
|
||||
t.Errorf(`Wrong output: %s`, output)
|
||||
if have != want {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImgWithSrcset(t *testing.T) {
|
||||
input := `<img srcset="example-320w.jpg, example-480w.jpg 1.5x, example-640w.jpg 2x, example-640w.jpg 640w" src="example-640w.jpg" alt="Example">`
|
||||
expected := `<img srcset="http://example.org/example-320w.jpg, http://example.org/example-480w.jpg 1.5x, http://example.org/example-640w.jpg 2x, http://example.org/example-640w.jpg 640w" src="http://example.org/example-640w.jpg" alt="Example" loading="lazy">`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<img srcset="http://example.org/example-320w.jpg, http://example.org/example-480w.jpg 1.5x, http://example.org/example-640w.jpg 2x, http://example.org/example-640w.jpg 640w" src="http://example.org/example-640w.jpg" alt="Example" loading="lazy" referrerpolicy="no-referrer">`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if output != expected {
|
||||
t.Errorf(`Wrong output: %s`, output)
|
||||
if have != want {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImgWithSrcsetAndDataURL(t *testing.T) {
|
||||
input := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example">`
|
||||
expected := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example" loading="lazy">`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<img srcset="data:image/gif;base64,test" src="http://example.org/example-320w.jpg" alt="Example" loading="lazy" referrerpolicy="no-referrer">`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if output != expected {
|
||||
t.Errorf(`Wrong output: %s`, output)
|
||||
if have != want {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,16 +68,16 @@ func TestSourceWithSrcsetAndMedia(t *testing.T) {
|
||||
|
||||
func TestMediumImgWithSrcset(t *testing.T) {
|
||||
input := `<img alt="Image for post" class="t u v ef aj" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" width="2730" height="3407">`
|
||||
expected := `<img alt="Image for post" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" loading="lazy">`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<img alt="Image for post" src="https://miro.medium.com/max/5460/1*aJ9JibWDqO81qMfNtqgqrw.jpeg" srcset="https://miro.medium.com/max/552/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 276w, https://miro.medium.com/max/1000/1*aJ9JibWDqO81qMfNtqgqrw.jpeg 500w" sizes="500px" loading="lazy" referrerpolicy="no-referrer">`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if output != expected {
|
||||
t.Errorf(`Wrong output: %s`, output)
|
||||
if have != want {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfClosingTags(t *testing.T) {
|
||||
input := `<p>This <br> is a <strong>text</strong> <br/>with an image: <img src="http://example.org/" alt="Test" loading="lazy"/>.</p>`
|
||||
input := `<p>This <br> is a <strong>text</strong><br/>.</p>`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
|
||||
if input != output {
|
||||
@@ -95,11 +96,11 @@ func TestTable(t *testing.T) {
|
||||
|
||||
func TestRelativeURL(t *testing.T) {
|
||||
input := `This <a href="/test.html">link is relative</a> and this image: <img src="../folder/image.png"/>`
|
||||
expected := `This <a href="http://example.org/test.html" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer">link is relative</a> and this image: <img src="http://example.org/folder/image.png" loading="lazy"/>`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `This <a href="http://example.org/test.html" rel="noopener noreferrer" target="_blank" referrerpolicy="no-referrer">link is relative</a> and this image: <img src="http://example.org/folder/image.png" loading="lazy" referrerpolicy="no-referrer"/>`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if expected != output {
|
||||
t.Errorf(`Wrong output: "%s" != "%s"`, expected, output)
|
||||
if want != have {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,11 +166,11 @@ func TestInvalidNestedTag(t *testing.T) {
|
||||
|
||||
func TestValidIFrame(t *testing.T) {
|
||||
input := `<iframe src="http://example.org/"></iframe>`
|
||||
expected := `<iframe src="http://example.org/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>`
|
||||
output := Sanitize("http://example.org/", input)
|
||||
want := `<iframe src="http://example.org/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>`
|
||||
have := Sanitize("http://example.org/", input)
|
||||
|
||||
if expected != output {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", expected, output)
|
||||
if want != have {
|
||||
t.Errorf("Wrong output:\nwant: %s\nhave: %s", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package scraper
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/content/htmlutil"
|
||||
@@ -35,6 +36,18 @@ func FindFeeds(body string, base string) map[string]string {
|
||||
link := htmlutil.AbsoluteUrl(href, base)
|
||||
if link != "" {
|
||||
candidates[link] = name
|
||||
|
||||
l, err := url.Parse(link)
|
||||
if err == nil && l.Host == "www.youtube.com" && l.Path == "/feeds/videos.xml" {
|
||||
// https://wiki.archiveteam.org/index.php/YouTube/Technical_details#Playlists
|
||||
channelID, found := strings.CutPrefix(l.Query().Get("channel_id"), "UC")
|
||||
if found {
|
||||
const url string = "https://www.youtube.com/feeds/videos.xml?playlist_id="
|
||||
candidates[url+"UULF"+channelID] = name + " - Videos"
|
||||
candidates[url+"UULV"+channelID] = name + " - Live Streams"
|
||||
candidates[url+"UUSH"+channelID] = name + " - Short videos"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package parser
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"html"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
@@ -47,6 +46,8 @@ type atomLinks []atomLink
|
||||
func (a *atomText) Text() string {
|
||||
if a.Type == "html" {
|
||||
return htmlutil.ExtractText(a.Data)
|
||||
} else if a.Type == "xhtml" {
|
||||
return htmlutil.ExtractText(a.XML)
|
||||
}
|
||||
return a.Data
|
||||
}
|
||||
@@ -56,7 +57,7 @@ func (a *atomText) String() string {
|
||||
if a.Type == "xhtml" {
|
||||
data = a.XML
|
||||
}
|
||||
return html.UnescapeString(strings.TrimSpace(data))
|
||||
return strings.TrimSpace(data)
|
||||
}
|
||||
|
||||
func (links atomLinks) First(rel string) string {
|
||||
@@ -81,15 +82,23 @@ func ParseAtom(r io.Reader) (*Feed, error) {
|
||||
SiteURL: firstNonEmpty(srcfeed.Links.First("alternate"), srcfeed.Links.First("")),
|
||||
}
|
||||
for _, srcitem := range srcfeed.Entries {
|
||||
link := firstNonEmpty(srcitem.OrigLink, srcitem.Links.First("alternate"), srcitem.Links.First(""))
|
||||
linkFromID := ""
|
||||
guidFromID := ""
|
||||
if htmlutil.IsAPossibleLink(srcitem.ID) {
|
||||
linkFromID = srcitem.ID
|
||||
guidFromID = srcitem.ID + "::" + srcitem.Updated
|
||||
}
|
||||
|
||||
mediaLinks := srcitem.mediaLinks()
|
||||
|
||||
link := firstNonEmpty(srcitem.OrigLink, srcitem.Links.First("alternate"), srcitem.Links.First(""), linkFromID)
|
||||
dstfeed.Items = append(dstfeed.Items, Item{
|
||||
GUID: firstNonEmpty(srcitem.ID, link),
|
||||
Date: dateParse(firstNonEmpty(srcitem.Published, srcitem.Updated)),
|
||||
URL: link,
|
||||
Title: srcitem.Title.Text(),
|
||||
Content: firstNonEmpty(srcitem.Content.String(), srcitem.Summary.String(), srcitem.firstMediaDescription()),
|
||||
ImageURL: srcitem.firstMediaThumbnail(),
|
||||
AudioURL: "",
|
||||
GUID: firstNonEmpty(guidFromID, srcitem.ID, link),
|
||||
Date: dateParse(firstNonEmpty(srcitem.Published, srcitem.Updated)),
|
||||
URL: link,
|
||||
Title: srcitem.Title.Text(),
|
||||
Content: firstNonEmpty(srcitem.Content.String(), srcitem.Summary.String(), srcitem.firstMediaDescription()),
|
||||
MediaLinks: mediaLinks,
|
||||
})
|
||||
}
|
||||
return dstfeed, nil
|
||||
|
||||
@@ -40,13 +40,11 @@ func TestAtom(t *testing.T) {
|
||||
SiteURL: "http://example.org/",
|
||||
Items: []Item{
|
||||
{
|
||||
GUID: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
|
||||
Date: time.Unix(1071340202, 0).UTC(),
|
||||
URL: "http://example.org/2003/12/13/atom03.html",
|
||||
Title: "Atom-Powered Robots Run Amok",
|
||||
Content: `<div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div>`,
|
||||
ImageURL: "",
|
||||
AudioURL: "",
|
||||
GUID: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
|
||||
Date: time.Unix(1071340202, 0).UTC(),
|
||||
URL: "http://example.org/2003/12/13/atom03.html",
|
||||
Title: "Atom-Powered Robots Run Amok",
|
||||
Content: `<div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div>`,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -94,6 +92,44 @@ func TestAtomHTMLTitle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomXHTMLTitle(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry><title type="xhtml">say <code>what</code>?</entry>
|
||||
</feed>
|
||||
`))
|
||||
have := feed.Items[0].Title
|
||||
want := "say what?"
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomXHTMLNestedTitle(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry>
|
||||
<title type="xhtml">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://example.com">Link to Example</a>
|
||||
</div>
|
||||
</title>
|
||||
</entry>
|
||||
</feed>
|
||||
`))
|
||||
have := feed.Items[0].Title
|
||||
want := "Link to Example"
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomImageLink(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -103,9 +139,15 @@ func TestAtomImageLink(t *testing.T) {
|
||||
</entry>
|
||||
</feed>
|
||||
`))
|
||||
have := feed.Items[0].ImageURL
|
||||
want := `https://example.com/image.png?width=100&height=100`
|
||||
if want != have {
|
||||
if len(feed.Items[0].MediaLinks) != 1 {
|
||||
t.Fatalf("Expected 1 media link, got: %#v", feed.Items[0].MediaLinks)
|
||||
}
|
||||
have := feed.Items[0].MediaLinks[0]
|
||||
want := MediaLink{
|
||||
URL: `https://example.com/image.png?width=100&height=100`,
|
||||
Type: "image",
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Fatalf("item.image_url doesn't match\nwant: %#v\nhave: %#v\n", want, have)
|
||||
}
|
||||
}
|
||||
@@ -127,7 +169,68 @@ func TestAtomImageLinkDuplicated(t *testing.T) {
|
||||
if want != have {
|
||||
t.Fatalf("want: %#v\nhave: %#v\n", want, have)
|
||||
}
|
||||
if feed.Items[0].ImageURL != "" {
|
||||
t.Fatal("item.image_url must be unset if present in the content")
|
||||
if len(feed.Items[0].MediaLinks) != 0 {
|
||||
t.Fatal("item media link must be excluded if present in the content")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomLinkInID(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
|
||||
<entry>
|
||||
<title>one updated</title>
|
||||
<id>https://example.com/posts/1</id>
|
||||
<updated>2003-12-13T09:17:51</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>two</title>
|
||||
<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>one</title>
|
||||
<id>https://example.com/posts/1</id>
|
||||
</entry>
|
||||
</feed>
|
||||
`))
|
||||
have := feed.Items
|
||||
want := []Item{
|
||||
Item{
|
||||
GUID: "https://example.com/posts/1::2003-12-13T09:17:51",
|
||||
Date: time.Date(2003, time.December, 13, 9, 17, 51, 0, time.UTC),
|
||||
URL: "https://example.com/posts/1",
|
||||
Title: "one updated",
|
||||
},
|
||||
Item{
|
||||
GUID: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
|
||||
Date: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), URL: "",
|
||||
Title: "two",
|
||||
},
|
||||
Item{
|
||||
GUID: "https://example.com/posts/1::",
|
||||
Date: time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
URL: "https://example.com/posts/1",
|
||||
Title: "one",
|
||||
Content: "",
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Fatalf("\nwant: %#v\nhave: %#v\n", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAtomDoesntEscapeHTMLTags(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<entry><summary type="html">&lt;script&gt;alert(1);&lt;/script&gt;</summary></entry>
|
||||
</feed>
|
||||
`))
|
||||
have := feed.Items[0].Content
|
||||
want := "<script>alert(1);</script>"
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package parser
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -119,6 +120,7 @@ func ParseAndFix(r io.Reader, baseURL, fallbackEncoding string) (*Feed, error) {
|
||||
}
|
||||
feed.TranslateURLs(baseURL)
|
||||
feed.SetMissingDatesTo(time.Now())
|
||||
feed.SetMissingGUIDs()
|
||||
return feed, nil
|
||||
}
|
||||
|
||||
@@ -132,11 +134,14 @@ func (feed *Feed) cleanup() {
|
||||
feed.Items[i].Title = strings.TrimSpace(htmlutil.ExtractText(item.Title))
|
||||
feed.Items[i].Content = strings.TrimSpace(item.Content)
|
||||
|
||||
if item.ImageURL != "" && strings.Contains(item.Content, item.ImageURL) {
|
||||
feed.Items[i].ImageURL = ""
|
||||
}
|
||||
if item.AudioURL != "" && strings.Contains(item.Content, item.AudioURL) {
|
||||
feed.Items[i].AudioURL = ""
|
||||
if len(feed.Items[i].MediaLinks) > 0 {
|
||||
mediaLinks := make([]MediaLink, 0)
|
||||
for _, link := range item.MediaLinks {
|
||||
if !strings.Contains(item.Content, link.URL) {
|
||||
mediaLinks = append(mediaLinks, link)
|
||||
}
|
||||
}
|
||||
feed.Items[i].MediaLinks = mediaLinks
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,3 +173,12 @@ func (feed *Feed) TranslateURLs(base string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (feed *Feed) SetMissingGUIDs() {
|
||||
for i, item := range feed.Items {
|
||||
if item.GUID == "" {
|
||||
id := strings.Join([]string{item.Title, item.Date.Format(time.RFC3339), item.URL}, ";;")
|
||||
feed.Items[i].GUID = fmt.Sprintf("%x", sha256.Sum256([]byte(id)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,3 +150,32 @@ func TestParseCleanIllegalCharsInNonUTF8(t *testing.T) {
|
||||
t.Fatalf("invalid feed, got: %v", feed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseMissingGUID(t *testing.T) {
|
||||
data := `
|
||||
<?xml version="1.0" encoding="windows-1251"?>
|
||||
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
|
||||
<channel>
|
||||
<item>
|
||||
<title>foo</title>
|
||||
</item>
|
||||
<item>
|
||||
<title>bar</title>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
`
|
||||
feed, err := ParseAndFix(strings.NewReader(data), "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(feed.Items) != 2 {
|
||||
t.Fatalf("expected 2 items, got %d", len(feed.Items))
|
||||
}
|
||||
if feed.Items[0].GUID == "" || feed.Items[1].GUID == "" {
|
||||
t.Fatalf("item GUIDs are missing, got %#v", feed.Items)
|
||||
}
|
||||
if feed.Items[0].GUID == feed.Items[1].GUID {
|
||||
t.Fatalf("item GUIDs are not unique, got %#v", feed.Items)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type media struct {
|
||||
MediaGroups []mediaGroup `xml:"http://search.yahoo.com/mrss/ group"`
|
||||
MediaContents []mediaContent `xml:"http://search.yahoo.com/mrss/ content"`
|
||||
@@ -8,12 +12,17 @@ type media struct {
|
||||
}
|
||||
|
||||
type mediaGroup struct {
|
||||
MediaContent []mediaContent `xml:"http://search.yahoo.com/mrss/ content"`
|
||||
MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"`
|
||||
MediaDescriptions []mediaDescription `xml:"http://search.yahoo.com/mrss/ description"`
|
||||
}
|
||||
|
||||
type mediaContent struct {
|
||||
MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"`
|
||||
MediaThumbnails []mediaThumbnail `xml:"http://search.yahoo.com/mrss/ thumbnail"`
|
||||
MediaType string `xml:"type,attr"`
|
||||
MediaMedium string `xml:"medium,attr"`
|
||||
MediaURL string `xml:"url,attr"`
|
||||
MediaDescription mediaDescription `xml:"http://search.yahoo.com/mrss/ description"`
|
||||
}
|
||||
|
||||
type mediaThumbnail struct {
|
||||
@@ -21,8 +30,8 @@ type mediaThumbnail struct {
|
||||
}
|
||||
|
||||
type mediaDescription struct {
|
||||
Type string `xml:"type,attr"`
|
||||
Description string `xml:",chardata"`
|
||||
Type string `xml:"type,attr"`
|
||||
Text string `xml:",chardata"`
|
||||
}
|
||||
|
||||
func (m *media) firstMediaThumbnail() string {
|
||||
@@ -44,12 +53,59 @@ func (m *media) firstMediaThumbnail() string {
|
||||
|
||||
func (m *media) firstMediaDescription() string {
|
||||
for _, d := range m.MediaDescriptions {
|
||||
return plain2html(d.Description)
|
||||
return plain2html(d.Text)
|
||||
}
|
||||
for _, g := range m.MediaGroups {
|
||||
for _, d := range g.MediaDescriptions {
|
||||
return plain2html(d.Description)
|
||||
return plain2html(d.Text)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *media) mediaLinks() []MediaLink {
|
||||
links := make([]MediaLink, 0)
|
||||
for _, thumbnail := range m.MediaThumbnails {
|
||||
links = append(links, MediaLink{URL: thumbnail.URL, Type: "image"})
|
||||
}
|
||||
for _, group := range m.MediaGroups {
|
||||
for _, thumbnail := range group.MediaThumbnails {
|
||||
links = append(links, MediaLink{
|
||||
URL: thumbnail.URL,
|
||||
Type: "image",
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, content := range m.MediaContents {
|
||||
if content.MediaURL != "" {
|
||||
url := content.MediaURL
|
||||
description := content.MediaDescription.Text
|
||||
if strings.HasPrefix(content.MediaType, "image/") {
|
||||
links = append(links, MediaLink{URL: url, Type: "image", Description: description})
|
||||
} else if strings.HasPrefix(content.MediaType, "audio/") {
|
||||
links = append(links, MediaLink{URL: url, Type: "audio", Description: description})
|
||||
} else if strings.HasPrefix(content.MediaType, "video/") {
|
||||
links = append(links, MediaLink{URL: url, Type: "video", Description: description})
|
||||
} else if content.MediaMedium == "image" || content.MediaMedium == "audio" || content.MediaMedium == "video" {
|
||||
links = append(links, MediaLink{URL: url, Type: content.MediaMedium, Description: description})
|
||||
} else {
|
||||
if len(content.MediaThumbnails) > 0 {
|
||||
links = append(links, MediaLink{
|
||||
URL: content.MediaThumbnails[0].URL,
|
||||
Type: "image",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, thumbnail := range content.MediaThumbnails {
|
||||
links = append(links, MediaLink{
|
||||
URL: thumbnail.URL,
|
||||
Type: "image",
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(links) == 0 {
|
||||
return nil
|
||||
}
|
||||
return links
|
||||
}
|
||||
|
||||
@@ -14,7 +14,12 @@ type Item struct {
|
||||
URL string
|
||||
Title string
|
||||
|
||||
Content string
|
||||
ImageURL string
|
||||
AudioURL string
|
||||
Content string
|
||||
MediaLinks []MediaLink
|
||||
}
|
||||
|
||||
type MediaLink struct {
|
||||
URL string
|
||||
Type string
|
||||
Description string
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ type rssFeed struct {
|
||||
}
|
||||
|
||||
type rssItem struct {
|
||||
GUID rssGuid `xml:"guid"`
|
||||
GUID rssGuid `xml:"guid"`
|
||||
Title string `xml:"title"`
|
||||
Link string `xml:"rss link"`
|
||||
Description string `xml:"rss description"`
|
||||
@@ -74,31 +74,30 @@ func ParseRSS(r io.Reader) (*Feed, error) {
|
||||
SiteURL: srcfeed.Link,
|
||||
}
|
||||
for _, srcitem := range srcfeed.Items {
|
||||
podcastURL := ""
|
||||
mediaLinks := srcitem.mediaLinks()
|
||||
for _, e := range srcitem.Enclosures {
|
||||
if strings.HasPrefix(e.Type, "audio/") {
|
||||
podcastURL = e.URL
|
||||
|
||||
podcastURL := e.URL
|
||||
if srcitem.OrigEnclosureLink != "" && strings.Contains(podcastURL, path.Base(srcitem.OrigEnclosureLink)) {
|
||||
podcastURL = srcitem.OrigEnclosureLink
|
||||
}
|
||||
mediaLinks = append(mediaLinks, MediaLink{URL: podcastURL, Type: "audio"})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
permalink := ""
|
||||
if srcitem.GUID.IsPermaLink == "true" {
|
||||
permalink = srcitem.GUID.GUID
|
||||
}
|
||||
permalink := ""
|
||||
if srcitem.GUID.IsPermaLink == "true" {
|
||||
permalink = srcitem.GUID.GUID
|
||||
}
|
||||
|
||||
dstfeed.Items = append(dstfeed.Items, Item{
|
||||
GUID: firstNonEmpty(srcitem.GUID.GUID, srcitem.Link),
|
||||
Date: dateParse(firstNonEmpty(srcitem.DublinCoreDate, srcitem.PubDate)),
|
||||
URL: firstNonEmpty(srcitem.OrigLink, srcitem.Link, permalink),
|
||||
Title: srcitem.Title,
|
||||
Content: firstNonEmpty(srcitem.ContentEncoded, srcitem.Description),
|
||||
AudioURL: podcastURL,
|
||||
ImageURL: srcitem.firstMediaThumbnail(),
|
||||
GUID: firstNonEmpty(srcitem.GUID.GUID, srcitem.Link),
|
||||
Date: dateParse(firstNonEmpty(srcitem.DublinCoreDate, srcitem.PubDate)),
|
||||
URL: firstNonEmpty(srcitem.OrigLink, srcitem.Link, permalink),
|
||||
Title: srcitem.Title,
|
||||
Content: firstNonEmpty(srcitem.ContentEncoded, srcitem.Description, srcitem.firstMediaDescription()),
|
||||
MediaLinks: mediaLinks,
|
||||
})
|
||||
}
|
||||
return dstfeed, nil
|
||||
|
||||
@@ -75,9 +75,15 @@ func TestRSSMediaContentThumbnail(t *testing.T) {
|
||||
</channel>
|
||||
</rss>
|
||||
`))
|
||||
have := feed.Items[0].ImageURL
|
||||
want := "https://i.vimeocdn.com/video/1092705247_960.jpg"
|
||||
if have != want {
|
||||
if len(feed.Items[0].MediaLinks) != 1 {
|
||||
t.Fatalf("Expected 1 media link, got %#v", feed.Items[0].MediaLinks)
|
||||
}
|
||||
have := feed.Items[0].MediaLinks[0]
|
||||
want := MediaLink{
|
||||
URL: "https://i.vimeocdn.com/video/1092705247_960.jpg",
|
||||
Type: "image",
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
@@ -127,9 +133,15 @@ func TestRSSPodcast(t *testing.T) {
|
||||
</channel>
|
||||
</rss>
|
||||
`))
|
||||
have := feed.Items[0].AudioURL
|
||||
want := "http://example.com/audio.ext"
|
||||
if want != have {
|
||||
if len(feed.Items[0].MediaLinks) != 1 {
|
||||
t.Fatal("Invalid media links")
|
||||
}
|
||||
have := feed.Items[0].MediaLinks[0]
|
||||
want := MediaLink{
|
||||
URL: "http://example.com/audio.ext",
|
||||
Type: "audio",
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
@@ -147,9 +159,15 @@ func TestRSSOpusPodcast(t *testing.T) {
|
||||
</channel>
|
||||
</rss>
|
||||
`))
|
||||
have := feed.Items[0].AudioURL
|
||||
want := "http://example.com/audio.ext"
|
||||
if want != have {
|
||||
if len(feed.Items[0].MediaLinks) != 1 {
|
||||
t.Fatal("Invalid media links")
|
||||
}
|
||||
have := feed.Items[0].MediaLinks[0]
|
||||
want := MediaLink{
|
||||
URL: "http://example.com/audio.ext",
|
||||
Type: "audio",
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.FailNow()
|
||||
@@ -176,8 +194,9 @@ func TestRSSPodcastDuplicated(t *testing.T) {
|
||||
if want != have {
|
||||
t.Fatalf("content doesn't match\nwant: %#v\nhave: %#v\n", want, have)
|
||||
}
|
||||
if feed.Items[0].AudioURL != "" {
|
||||
t.Fatal("item.audio_url must be unset if present in the content")
|
||||
|
||||
if len(feed.Items[0].MediaLinks) != 0 {
|
||||
t.Fatal("item media must be excluded if present in the content")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,14 +236,53 @@ func TestRSSIsPermalink(t *testing.T) {
|
||||
`))
|
||||
have := feed.Items
|
||||
want := []Item{
|
||||
{
|
||||
GUID: "http://example.com/posts/1",
|
||||
URL: "http://example.com/posts/1",
|
||||
},
|
||||
}
|
||||
{
|
||||
GUID: "http://example.com/posts/1",
|
||||
URL: "http://example.com/posts/1",
|
||||
},
|
||||
}
|
||||
for i := 0; i < len(want); i++ {
|
||||
if want[i] != have[i] {
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Errorf("Failed to handle isPermalink\nwant: %#v\nhave: %#v\n", want[i], have[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRSSMultipleMedia(t *testing.T) {
|
||||
feed, _ := Parse(strings.NewReader(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
|
||||
<channel>
|
||||
<item>
|
||||
<guid isPermaLink="true">http://example.com/posts/1</guid>
|
||||
<media:content url="https://example.com/path/to/image1.png" type="image/png" fileSize="1000" medium="image">
|
||||
<media:description type="plain">description 1</media:description>
|
||||
</media:content>
|
||||
<media:content url="https://example.com/path/to/image2.png" type="image/png" fileSize="2000" medium="image">
|
||||
<media:description type="plain">description 2</media:description>
|
||||
</media:content>
|
||||
<media:content url="https://example.com/path/to/video1.mp4" type="video/mp4" fileSize="2000" medium="image">
|
||||
<media:description type="plain">video description</media:description>
|
||||
</media:content>
|
||||
</item>
|
||||
</channel>
|
||||
</rss>
|
||||
`))
|
||||
have := feed.Items
|
||||
want := []Item{
|
||||
{
|
||||
GUID: "http://example.com/posts/1",
|
||||
URL: "http://example.com/posts/1",
|
||||
MediaLinks: []MediaLink{
|
||||
{URL:"https://example.com/path/to/image1.png", Type:"image", Description:"description 1"},
|
||||
{URL:"https://example.com/path/to/image2.png", Type:"image", Description:"description 2"},
|
||||
{URL:"https://example.com/path/to/video1.mp4", Type:"video", Description:"video description"},
|
||||
},
|
||||
},
|
||||
}
|
||||
if !reflect.DeepEqual(want, have) {
|
||||
t.Logf("want: %#v", want)
|
||||
t.Logf("have: %#v", have)
|
||||
t.Fatal("invalid rss")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
func Start(s *server.Server) {
|
||||
systrayOnReady := func() {
|
||||
systray.SetIcon(Icon)
|
||||
systray.SetTooltip("yarr")
|
||||
|
||||
menuOpen := systray.AddMenuItem("Open", "")
|
||||
systray.AddSeparator()
|
||||
|
||||
@@ -6,13 +6,15 @@ import (
|
||||
|
||||
"github.com/nkanaev/yarr/src/assets"
|
||||
"github.com/nkanaev/yarr/src/server/router"
|
||||
"github.com/nkanaev/yarr/src/storage"
|
||||
)
|
||||
|
||||
type Middleware struct {
|
||||
Username string
|
||||
Password string
|
||||
BasePath string
|
||||
Public string
|
||||
Public []string
|
||||
DB *storage.Storage
|
||||
}
|
||||
|
||||
func unsafeMethod(method string) bool {
|
||||
@@ -20,9 +22,11 @@ func unsafeMethod(method string) bool {
|
||||
}
|
||||
|
||||
func (m *Middleware) Handler(c *router.Context) {
|
||||
if strings.HasPrefix(c.Req.URL.Path, m.BasePath+m.Public) {
|
||||
c.Next()
|
||||
return
|
||||
for _, path := range m.Public {
|
||||
if strings.HasPrefix(c.Req.URL.Path, m.BasePath+path) {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
}
|
||||
if IsAuthenticated(c.Req, m.Username, m.Password) {
|
||||
c.Next()
|
||||
@@ -44,12 +48,15 @@ func (m *Middleware) Handler(c *router.Context) {
|
||||
c.Redirect(rootUrl)
|
||||
return
|
||||
} else {
|
||||
c.HTML(http.StatusOK, assets.Template("login.html"), map[string]string{
|
||||
c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{
|
||||
"username": username,
|
||||
"error": "Invalid username/password",
|
||||
"settings": m.DB.GetSettings(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.HTML(http.StatusOK, assets.Template("login.html"), nil)
|
||||
c.HTML(http.StatusOK, assets.Template("login.html"), map[string]interface{}{
|
||||
"settings": m.DB.GetSettings(),
|
||||
})
|
||||
}
|
||||
|
||||
393
src/server/fever.go
Normal file
393
src/server/fever.go
Normal file
@@ -0,0 +1,393 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/nkanaev/yarr/src/server/auth"
|
||||
"github.com/nkanaev/yarr/src/server/router"
|
||||
"github.com/nkanaev/yarr/src/storage"
|
||||
)
|
||||
|
||||
type FeverGroup struct {
|
||||
ID int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
|
||||
type FeverFeedsGroup struct {
|
||||
GroupID int64 `json:"group_id"`
|
||||
FeedIDs string `json:"feed_ids"`
|
||||
}
|
||||
|
||||
type FeverFeed struct {
|
||||
ID int64 `json:"id"`
|
||||
FaviconID int64 `json:"favicon_id"`
|
||||
Title string `json:"title"`
|
||||
Url string `json:"url"`
|
||||
SiteUrl string `json:"site_url"`
|
||||
IsSpark int `json:"is_spark"`
|
||||
LastUpdated int64 `json:"last_updated_on_time"`
|
||||
}
|
||||
|
||||
type FeverItem struct {
|
||||
ID int64 `json:"id"`
|
||||
FeedID int64 `json:"feed_id"`
|
||||
Title string `json:"title"`
|
||||
Author string `json:"author"`
|
||||
HTML string `json:"html"`
|
||||
Url string `json:"url"`
|
||||
IsSaved int `json:"is_saved"`
|
||||
IsRead int `json:"is_read"`
|
||||
CreatedAt int64 `json:"created_on_time"`
|
||||
}
|
||||
|
||||
type FeverFavicon struct {
|
||||
ID int64 `json:"id"`
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
func writeFeverJSON(c *router.Context, data map[string]interface{}, lastRefreshed int64) {
|
||||
data["api_version"] = 3
|
||||
data["auth"] = 1
|
||||
data["last_refreshed_on_time"] = lastRefreshed
|
||||
c.JSON(http.StatusOK, data)
|
||||
}
|
||||
|
||||
func getLastRefreshedOnTime(httpStates map[int64]storage.HTTPState) int64 {
|
||||
if len(httpStates) == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
var lastRefreshed int64
|
||||
for _, state := range httpStates {
|
||||
if state.LastRefreshed.Unix() > lastRefreshed {
|
||||
lastRefreshed = state.LastRefreshed.Unix()
|
||||
}
|
||||
}
|
||||
return lastRefreshed
|
||||
}
|
||||
|
||||
func (s *Server) feverAuth(c *router.Context) bool {
|
||||
if s.Username != "" && s.Password != "" {
|
||||
apiKey := c.Req.FormValue("api_key")
|
||||
apiKey = strings.ToLower(apiKey)
|
||||
md5HashValue := md5.Sum([]byte(fmt.Sprintf("%s:%s", s.Username, s.Password)))
|
||||
hexMD5HashValue := fmt.Sprintf("%x", md5HashValue[:])
|
||||
if !auth.StringsEqual(apiKey, hexMD5HashValue) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func formHasValue(values url.Values, value string) bool {
|
||||
if _, ok := values[value]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *Server) handleFever(c *router.Context) {
|
||||
c.Req.ParseForm()
|
||||
if !s.feverAuth(c) {
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"api_version": 3,
|
||||
"auth": 0,
|
||||
"last_refreshed_on_time": 0,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
switch {
|
||||
case formHasValue(c.Req.Form, "groups"):
|
||||
s.feverGroupsHandler(c)
|
||||
case formHasValue(c.Req.Form, "feeds"):
|
||||
s.feverFeedsHandler(c)
|
||||
case formHasValue(c.Req.Form, "unread_item_ids"):
|
||||
s.feverUnreadItemIDsHandler(c)
|
||||
case formHasValue(c.Req.Form, "saved_item_ids"):
|
||||
s.feverSavedItemIDsHandler(c)
|
||||
case formHasValue(c.Req.Form, "favicons"):
|
||||
s.feverFaviconsHandler(c)
|
||||
case formHasValue(c.Req.Form, "items"):
|
||||
s.feverItemsHandler(c)
|
||||
case formHasValue(c.Req.Form, "links"):
|
||||
s.feverLinksHandler(c)
|
||||
case formHasValue(c.Req.Form, "mark"):
|
||||
s.feverMarkHandler(c)
|
||||
default:
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"api_version": 3,
|
||||
"auth": 1,
|
||||
"last_refreshed_on_time": getLastRefreshedOnTime(s.db.ListHTTPStates()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func joinInts(values []int64) string {
|
||||
var result strings.Builder
|
||||
for i, val := range values {
|
||||
fmt.Fprintf(&result, "%d", val)
|
||||
if i != len(values)-1 {
|
||||
result.WriteString(",")
|
||||
}
|
||||
}
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func feedGroups(db *storage.Storage) []*FeverFeedsGroup {
|
||||
feeds := db.ListFeeds()
|
||||
|
||||
groupFeeds := make(map[int64][]int64)
|
||||
for _, feed := range feeds {
|
||||
if feed.FolderId == nil {
|
||||
continue
|
||||
}
|
||||
groupFeeds[*feed.FolderId] = append(groupFeeds[*feed.FolderId], feed.Id)
|
||||
}
|
||||
result := make([]*FeverFeedsGroup, 0)
|
||||
for groupId, feedIds := range groupFeeds {
|
||||
result = append(result, &FeverFeedsGroup{
|
||||
GroupID: groupId,
|
||||
FeedIDs: joinInts(feedIds),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (s *Server) feverGroupsHandler(c *router.Context) {
|
||||
folders := s.db.ListFolders()
|
||||
groups := make([]*FeverGroup, len(folders))
|
||||
for i, folder := range folders {
|
||||
groups[i] = &FeverGroup{ID: folder.Id, Title: folder.Title}
|
||||
}
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"groups": groups,
|
||||
"feeds_groups": feedGroups(s.db),
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
func (s *Server) feverFeedsHandler(c *router.Context) {
|
||||
feeds := s.db.ListFeeds()
|
||||
httpStates := s.db.ListHTTPStates()
|
||||
|
||||
feverFeeds := make([]*FeverFeed, len(feeds))
|
||||
for i, feed := range feeds {
|
||||
var lastUpdated int64
|
||||
if state, ok := httpStates[feed.Id]; ok {
|
||||
lastUpdated = state.LastRefreshed.Unix()
|
||||
}
|
||||
feverFeeds[i] = &FeverFeed{
|
||||
ID: feed.Id,
|
||||
FaviconID: feed.Id,
|
||||
Title: feed.Title,
|
||||
Url: feed.FeedLink,
|
||||
SiteUrl: feed.Link,
|
||||
IsSpark: 0,
|
||||
LastUpdated: lastUpdated,
|
||||
}
|
||||
}
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"feeds": feverFeeds,
|
||||
"feeds_groups": feedGroups(s.db),
|
||||
}, getLastRefreshedOnTime(httpStates))
|
||||
}
|
||||
|
||||
func (s *Server) feverFaviconsHandler(c *router.Context) {
|
||||
feeds := s.db.ListFeeds()
|
||||
favicons := make([]*FeverFavicon, len(feeds))
|
||||
for i, feed := range feeds {
|
||||
data := "data:image/gif;base64,R0lGODlhAQABAAAAACw="
|
||||
if feed.HasIcon {
|
||||
icon := s.db.GetFeed(feed.Id).Icon
|
||||
data = fmt.Sprintf(
|
||||
"data:%s;base64,%s",
|
||||
http.DetectContentType(*icon),
|
||||
base64.StdEncoding.EncodeToString(*icon),
|
||||
)
|
||||
}
|
||||
favicons[i] = &FeverFavicon{ID: feed.Id, Data: data}
|
||||
}
|
||||
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"favicons": favicons,
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
// for memory pressure reasons, we only return a limited number of items
|
||||
// documented at https://github.com/DigitalDJ/tinytinyrss-fever-plugin/blob/master/fever-api.md#items
|
||||
const listLimit = 50
|
||||
|
||||
func (s *Server) feverItemsHandler(c *router.Context) {
|
||||
filter := storage.ItemFilter{}
|
||||
query := c.Req.URL.Query()
|
||||
|
||||
switch {
|
||||
case query.Get("with_ids") != "":
|
||||
ids := make([]int64, 0)
|
||||
for _, idstr := range strings.Split(query.Get("with_ids"), ",") {
|
||||
if idnum, err := strconv.ParseInt(idstr, 10, 64); err == nil {
|
||||
ids = append(ids, idnum)
|
||||
}
|
||||
}
|
||||
filter.IDs = &ids
|
||||
case query.Get("since_id") != "":
|
||||
idstr := query.Get("since_id")
|
||||
if idnum, err := strconv.ParseInt(idstr, 10, 64); err == nil {
|
||||
filter.SinceID = &idnum
|
||||
}
|
||||
case query.Get("max_id") != "":
|
||||
idstr := query.Get("max_id")
|
||||
if idnum, err := strconv.ParseInt(idstr, 10, 64); err == nil {
|
||||
filter.MaxID = &idnum
|
||||
}
|
||||
}
|
||||
|
||||
items := s.db.ListItems(filter, listLimit, true, true)
|
||||
|
||||
feverItems := make([]FeverItem, len(items))
|
||||
for i, item := range items {
|
||||
date := item.Date
|
||||
time := date.Unix()
|
||||
|
||||
isSaved := 0
|
||||
if item.Status == storage.STARRED {
|
||||
isSaved = 1
|
||||
}
|
||||
isRead := 0
|
||||
if item.Status == storage.READ {
|
||||
isRead = 1
|
||||
}
|
||||
feverItems[i] = FeverItem{
|
||||
ID: item.Id,
|
||||
FeedID: item.FeedId,
|
||||
Title: item.Title,
|
||||
Author: "",
|
||||
HTML: item.Content,
|
||||
Url: item.Link,
|
||||
IsSaved: isSaved,
|
||||
IsRead: isRead,
|
||||
CreatedAt: time,
|
||||
}
|
||||
}
|
||||
|
||||
totalItems := s.db.CountItems(storage.ItemFilter{})
|
||||
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"items": feverItems,
|
||||
"total_items": totalItems,
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
func (s *Server) feverLinksHandler(c *router.Context) {
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"links": make([]interface{}, 0),
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
func (s *Server) feverUnreadItemIDsHandler(c *router.Context) {
|
||||
status := storage.UNREAD
|
||||
itemIds := make([]int64, 0)
|
||||
|
||||
itemFilter := storage.ItemFilter{
|
||||
Status: &status,
|
||||
}
|
||||
for {
|
||||
items := s.db.ListItems(itemFilter, listLimit, true, false)
|
||||
if len(items) == 0 {
|
||||
break
|
||||
}
|
||||
for _, item := range items {
|
||||
itemIds = append(itemIds, item.Id)
|
||||
}
|
||||
itemFilter.After = &items[len(items)-1].Id
|
||||
}
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"unread_item_ids": joinInts(itemIds),
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
func (s *Server) feverSavedItemIDsHandler(c *router.Context) {
|
||||
status := storage.STARRED
|
||||
itemIds := make([]int64, 0)
|
||||
|
||||
itemFilter := storage.ItemFilter{
|
||||
Status: &status,
|
||||
}
|
||||
for {
|
||||
items := s.db.ListItems(itemFilter, listLimit, true, false)
|
||||
if len(items) == 0 {
|
||||
break
|
||||
}
|
||||
for _, item := range items {
|
||||
itemIds = append(itemIds, item.Id)
|
||||
}
|
||||
itemFilter.After = &items[len(items)-1].Id
|
||||
}
|
||||
writeFeverJSON(c, map[string]interface{}{
|
||||
"saved_item_ids": joinInts(itemIds),
|
||||
}, getLastRefreshedOnTime(s.db.ListHTTPStates()))
|
||||
}
|
||||
|
||||
func (s *Server) feverMarkHandler(c *router.Context) {
|
||||
id, err := strconv.ParseInt(c.Req.Form.Get("id"), 10, 64)
|
||||
if err != nil {
|
||||
log.Print("invalid id:", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch c.Req.Form.Get("mark") {
|
||||
case "item":
|
||||
var status storage.ItemStatus
|
||||
switch c.Req.Form.Get("as") {
|
||||
case "read":
|
||||
status = storage.READ
|
||||
case "unread":
|
||||
status = storage.UNREAD
|
||||
case "saved":
|
||||
status = storage.STARRED
|
||||
case "unsaved":
|
||||
status = storage.READ
|
||||
default:
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
s.db.UpdateItemStatus(id, status)
|
||||
case "feed":
|
||||
if c.Req.Form.Get("as") != "read" {
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
markFilter := storage.MarkFilter{FeedID: &id}
|
||||
x, _ := strconv.ParseInt(c.Req.Form.Get("before"), 10, 64)
|
||||
if x > 0 {
|
||||
before := time.Unix(x, 0)
|
||||
markFilter.Before = &before
|
||||
}
|
||||
s.db.MarkItemsRead(markFilter)
|
||||
case "group":
|
||||
if c.Req.Form.Get("as") != "read" {
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
markFilter := storage.MarkFilter{FolderID: &id}
|
||||
x, _ := strconv.ParseInt(c.Req.Form.Get("before"), 10, 64)
|
||||
if x > 0 {
|
||||
before := time.Unix(x, 0)
|
||||
markFilter.Before = &before
|
||||
}
|
||||
s.db.MarkItemsRead(markFilter)
|
||||
default:
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"api_version": 3,
|
||||
"auth": 1,
|
||||
})
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/nkanaev/yarr/src/assets"
|
||||
"github.com/nkanaev/yarr/src/content/htmlutil"
|
||||
"github.com/nkanaev/yarr/src/content/readability"
|
||||
"github.com/nkanaev/yarr/src/content/sanitizer"
|
||||
"github.com/nkanaev/yarr/src/content/silo"
|
||||
@@ -33,7 +34,8 @@ func (s *Server) handler() http.Handler {
|
||||
BasePath: s.BasePath,
|
||||
Username: s.Username,
|
||||
Password: s.Password,
|
||||
Public: "/static",
|
||||
Public: []string{"/static", "/fever"},
|
||||
DB: s.db,
|
||||
}
|
||||
r.Use(a.Handler)
|
||||
}
|
||||
@@ -56,6 +58,7 @@ func (s *Server) handler() http.Handler {
|
||||
r.For("/opml/export", s.handleOPMLExport)
|
||||
r.For("/page", s.handlePageCrawl)
|
||||
r.For("/logout", s.handleLogout)
|
||||
r.For("/fever/", s.handleFever)
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -84,7 +87,7 @@ func (s *Server) handleManifest(c *router.Context) {
|
||||
"short_name": "yarr",
|
||||
"description": "yet another rss reader",
|
||||
"display": "standalone",
|
||||
"start_url": s.BasePath,
|
||||
"start_url": "/" + strings.TrimPrefix(s.BasePath, "/"),
|
||||
"icons": []map[string]interface{}{
|
||||
{
|
||||
"src": s.BasePath + "/static/graphicarts/favicon.png",
|
||||
@@ -291,6 +294,11 @@ func (s *Server) handleFeed(c *router.Context) {
|
||||
s.db.UpdateFeedFolder(id, &folderId)
|
||||
}
|
||||
}
|
||||
if link, ok := body["feed_link"]; ok {
|
||||
if reflect.TypeOf(link).Kind() == reflect.String {
|
||||
s.db.UpdateFeedLink(id, link.(string))
|
||||
}
|
||||
}
|
||||
c.Out.WriteHeader(http.StatusOK)
|
||||
} else if c.Req.Method == "DELETE" {
|
||||
s.db.DeleteFeed(id)
|
||||
@@ -312,7 +320,18 @@ func (s *Server) handleItem(c *router.Context) {
|
||||
c.Out.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// runtime fix for relative links
|
||||
if !htmlutil.IsAPossibleLink(item.Link) {
|
||||
if feed := s.db.GetFeed(item.FeedId); feed != nil {
|
||||
item.Link = htmlutil.AbsoluteUrl(item.Link, feed.Link)
|
||||
}
|
||||
}
|
||||
|
||||
item.Content = sanitizer.Sanitize(item.Link, item.Content)
|
||||
for i, link := range item.MediaLinks {
|
||||
item.MediaLinks[i].Description = sanitizer.Sanitize(item.Link, link.Description)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, item)
|
||||
} else if c.Req.Method == "PUT" {
|
||||
@@ -355,12 +374,19 @@ func (s *Server) handleItemList(c *router.Context) {
|
||||
}
|
||||
newestFirst := query.Get("oldest_first") != "true"
|
||||
|
||||
items := s.db.ListItems(filter, perPage+1, newestFirst)
|
||||
items := s.db.ListItems(filter, perPage+1, newestFirst, true)
|
||||
hasMore := false
|
||||
if len(items) == perPage+1 {
|
||||
hasMore = true
|
||||
items = items[:perPage]
|
||||
}
|
||||
|
||||
for i, item := range items {
|
||||
if item.Title == "" {
|
||||
text := htmlutil.ExtractText(item.Content)
|
||||
items[i].Title = htmlutil.TruncateText(text, 140)
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, map[string]interface{}{
|
||||
"list": items,
|
||||
"has_more": hasMore,
|
||||
|
||||
@@ -20,18 +20,19 @@ func (s *Storage) CreateFeed(title, description, link, feedLink string, folderId
|
||||
if title == "" {
|
||||
title = feedLink
|
||||
}
|
||||
result, err := s.db.Exec(`
|
||||
row := s.db.QueryRow(`
|
||||
insert into feeds (title, description, link, feed_link, folder_id)
|
||||
values (?, ?, ?, ?, ?)
|
||||
on conflict (feed_link) do update set folder_id=?`,
|
||||
on conflict (feed_link) do update set folder_id = ?
|
||||
returning id`,
|
||||
title, description, link, feedLink, folderId,
|
||||
folderId,
|
||||
)
|
||||
|
||||
var id int64
|
||||
err := row.Scan(&id)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
id, idErr := result.LastInsertId()
|
||||
if idErr != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
return &Feed{
|
||||
@@ -70,6 +71,11 @@ func (s *Storage) UpdateFeedFolder(feedId int64, newFolderId *int64) bool {
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (s *Storage) UpdateFeedLink(feedId int64, newLink string) bool {
|
||||
_, err := s.db.Exec(`update feeds set feed_link = ? where id = ?`, newLink, feedId)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (s *Storage) UpdateFeedIcon(feedId int64, icon *[]byte) bool {
|
||||
_, err := s.db.Exec(`update feeds set icon = ? where id = ?`, icon, feedId)
|
||||
return err == nil
|
||||
|
||||
@@ -17,6 +17,23 @@ func TestCreateFeed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateFeedSameLink(t *testing.T) {
|
||||
db := testDB()
|
||||
feed1 := db.CreateFeed("title", "", "", "http://example1.com/feed.xml", nil)
|
||||
if feed1 == nil || feed1.Id == 0 {
|
||||
t.Fatal("expected feed")
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
db.CreateFeed("title", "", "", "http://example2.com/feed.xml", nil)
|
||||
}
|
||||
|
||||
feed2 := db.CreateFeed("title", "", "http://example.com", "http://example1.com/feed.xml", nil)
|
||||
if feed1.Id != feed2.Id {
|
||||
t.Fatalf("expected the same feed.\nwant: %#v\nhave: %#v", feed1, feed2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadFeed(t *testing.T) {
|
||||
db := testDB()
|
||||
if db.GetFeed(100500) != nil {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
@@ -13,35 +12,21 @@ type Folder struct {
|
||||
|
||||
func (s *Storage) CreateFolder(title string) *Folder {
|
||||
expanded := true
|
||||
result, err := s.db.Exec(`
|
||||
row := s.db.QueryRow(`
|
||||
insert into folders (title, is_expanded) values (?, ?)
|
||||
on conflict (title) do nothing`,
|
||||
on conflict (title) do update set title = ?
|
||||
returning id`,
|
||||
title, expanded,
|
||||
// provide title again so that we can extract row id
|
||||
title,
|
||||
)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var id int64
|
||||
numrows, err := result.RowsAffected()
|
||||
err := row.Scan(&id)
|
||||
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
if numrows == 1 {
|
||||
id, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
err = s.db.QueryRow(`select id, is_expanded from folders where title=?`, title).Scan(&id, &expanded)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return &Folder{Id: id, Title: title, IsExpanded: expanded}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -43,17 +45,35 @@ func (s *ItemStatus) UnmarshalJSON(b []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type MediaLink struct {
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
type MediaLinks []MediaLink
|
||||
|
||||
func (m *MediaLinks) Scan(src any) error {
|
||||
if data, ok := src.([]byte); ok {
|
||||
return json.Unmarshal(data, m)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m MediaLinks) Value() (driver.Value, error) {
|
||||
return json.Marshal(m)
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
Id int64 `json:"id"`
|
||||
GUID string `json:"guid"`
|
||||
FeedId int64 `json:"feed_id"`
|
||||
Title string `json:"title"`
|
||||
Link string `json:"link"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Date time.Time `json:"date"`
|
||||
Status ItemStatus `json:"status"`
|
||||
ImageURL *string `json:"image"`
|
||||
AudioURL *string `json:"podcast_url"`
|
||||
Id int64 `json:"id"`
|
||||
GUID string `json:"guid"`
|
||||
FeedId int64 `json:"feed_id"`
|
||||
Title string `json:"title"`
|
||||
Link string `json:"link"`
|
||||
Content string `json:"content,omitempty"`
|
||||
Date time.Time `json:"date"`
|
||||
Status ItemStatus `json:"status"`
|
||||
MediaLinks MediaLinks `json:"media_links"`
|
||||
}
|
||||
|
||||
type ItemFilter struct {
|
||||
@@ -62,11 +82,35 @@ type ItemFilter struct {
|
||||
Status *ItemStatus
|
||||
Search *string
|
||||
After *int64
|
||||
IDs *[]int64
|
||||
SinceID *int64
|
||||
MaxID *int64
|
||||
Before *time.Time
|
||||
}
|
||||
|
||||
type MarkFilter struct {
|
||||
FolderID *int64
|
||||
FeedID *int64
|
||||
|
||||
Before *time.Time
|
||||
}
|
||||
|
||||
type ItemList []Item
|
||||
|
||||
func (list ItemList) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list ItemList) SortKey(i int) string {
|
||||
return list[i].Date.Format(time.RFC3339) + "::" + list[i].GUID
|
||||
}
|
||||
|
||||
func (list ItemList) Less(i, j int) bool {
|
||||
return list.SortKey(i) < list.SortKey(j)
|
||||
}
|
||||
|
||||
func (list ItemList) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func (s *Storage) CreateItems(items []Item) bool {
|
||||
@@ -78,17 +122,24 @@ func (s *Storage) CreateItems(items []Item) bool {
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
for _, item := range items {
|
||||
itemsSorted := ItemList(items)
|
||||
sort.Sort(itemsSorted)
|
||||
|
||||
for _, item := range itemsSorted {
|
||||
_, err = tx.Exec(`
|
||||
insert into items (
|
||||
guid, feed_id, title, link, date,
|
||||
content, image, podcast_url,
|
||||
content, media_links,
|
||||
date_arrived, status
|
||||
)
|
||||
values (?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', ?), ?, ?, ?, ?, ?)
|
||||
values (
|
||||
?, ?, ?, ?, strftime('%Y-%m-%d %H:%M:%f', ?),
|
||||
?, ?,
|
||||
?, ?
|
||||
)
|
||||
on conflict (feed_id, guid) do nothing`,
|
||||
item.GUID, item.FeedId, item.Title, item.Link, item.Date,
|
||||
item.Content, item.ImageURL, item.AudioURL,
|
||||
item.Content, item.MediaLinks,
|
||||
now, UNREAD,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -140,6 +191,28 @@ func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interfac
|
||||
cond = append(cond, fmt.Sprintf("(i.date, i.id) %s (select date, id from items where id = ?)", compare))
|
||||
args = append(args, *filter.After)
|
||||
}
|
||||
if filter.IDs != nil && len(*filter.IDs) > 0 {
|
||||
qmarks := make([]string, len(*filter.IDs))
|
||||
idargs := make([]interface{}, len(*filter.IDs))
|
||||
for i, id := range *filter.IDs {
|
||||
qmarks[i] = "?"
|
||||
idargs[i] = id
|
||||
}
|
||||
cond = append(cond, "i.id in ("+strings.Join(qmarks, ",")+")")
|
||||
args = append(args, idargs...)
|
||||
}
|
||||
if filter.SinceID != nil {
|
||||
cond = append(cond, "i.id > ?")
|
||||
args = append(args, filter.SinceID)
|
||||
}
|
||||
if filter.MaxID != nil {
|
||||
cond = append(cond, "i.id < ?")
|
||||
args = append(args, filter.MaxID)
|
||||
}
|
||||
if filter.Before != nil {
|
||||
cond = append(cond, "i.date < ?")
|
||||
args = append(args, filter.Before)
|
||||
}
|
||||
|
||||
predicate := "1"
|
||||
if len(cond) > 0 {
|
||||
@@ -149,7 +222,24 @@ func listQueryPredicate(filter ItemFilter, newestFirst bool) (string, []interfac
|
||||
return predicate, args
|
||||
}
|
||||
|
||||
func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool) []Item {
|
||||
func (s *Storage) CountItems(filter ItemFilter) int {
|
||||
predicate, args := listQueryPredicate(filter, false)
|
||||
|
||||
var count int
|
||||
query := fmt.Sprintf(`
|
||||
select count(*)
|
||||
from items
|
||||
where %s
|
||||
`, predicate)
|
||||
err := s.db.QueryRow(query, args...).Scan(&count)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
return 0
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool, withContent bool) []Item {
|
||||
predicate, args := listQueryPredicate(filter, newestFirst)
|
||||
result := make([]Item, 0, 0)
|
||||
|
||||
@@ -157,17 +247,26 @@ func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool) []It
|
||||
if !newestFirst {
|
||||
order = "date asc, id asc"
|
||||
}
|
||||
if filter.IDs != nil || filter.SinceID != nil {
|
||||
order = "i.id asc"
|
||||
}
|
||||
if filter.MaxID != nil {
|
||||
order = "i.id desc"
|
||||
}
|
||||
|
||||
selectCols := "i.id, i.guid, i.feed_id, i.title, i.link, i.date, i.status, i.media_links"
|
||||
if withContent {
|
||||
selectCols += ", i.content"
|
||||
} else {
|
||||
selectCols += ", '' as content"
|
||||
}
|
||||
query := fmt.Sprintf(`
|
||||
select
|
||||
i.id, i.guid, i.feed_id,
|
||||
i.title, i.link, i.date,
|
||||
i.status, i.image, i.podcast_url
|
||||
select %s
|
||||
from items i
|
||||
where %s
|
||||
order by %s
|
||||
limit %d
|
||||
`, predicate, order, limit)
|
||||
`, selectCols, predicate, order, limit)
|
||||
rows, err := s.db.Query(query, args...)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@@ -178,7 +277,7 @@ func (s *Storage) ListItems(filter ItemFilter, limit int, newestFirst bool) []It
|
||||
err = rows.Scan(
|
||||
&x.Id, &x.GUID, &x.FeedId,
|
||||
&x.Title, &x.Link, &x.Date,
|
||||
&x.Status, &x.ImageURL, &x.AudioURL,
|
||||
&x.Status, &x.MediaLinks, &x.Content,
|
||||
)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@@ -194,12 +293,12 @@ func (s *Storage) GetItem(id int64) *Item {
|
||||
err := s.db.QueryRow(`
|
||||
select
|
||||
i.id, i.guid, i.feed_id, i.title, i.link, i.content,
|
||||
i.date, i.status, i.image, i.podcast_url
|
||||
i.date, i.status, i.media_links
|
||||
from items i
|
||||
where i.id = ?
|
||||
`, id).Scan(
|
||||
&i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content,
|
||||
&i.Date, &i.Status, &i.ImageURL, &i.AudioURL,
|
||||
&i.Date, &i.Status, &i.MediaLinks,
|
||||
)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
@@ -214,7 +313,11 @@ func (s *Storage) UpdateItemStatus(item_id int64, status ItemStatus) bool {
|
||||
}
|
||||
|
||||
func (s *Storage) MarkItemsRead(filter MarkFilter) bool {
|
||||
predicate, args := listQueryPredicate(ItemFilter{FolderID: filter.FolderID, FeedID: filter.FeedID}, false)
|
||||
predicate, args := listQueryPredicate(ItemFilter{
|
||||
FolderID: filter.FolderID,
|
||||
FeedID: filter.FeedID,
|
||||
Before: filter.Before,
|
||||
}, false)
|
||||
query := fmt.Sprintf(`
|
||||
update items as i set status = %d
|
||||
where %s and i.status != %d
|
||||
|
||||
@@ -77,12 +77,12 @@ func getItem(db *Storage, guid string) *Item {
|
||||
err := db.db.QueryRow(`
|
||||
select
|
||||
i.id, i.guid, i.feed_id, i.title, i.link, i.content,
|
||||
i.date, i.status, i.image, i.podcast_url
|
||||
i.date, i.status, i.media_links
|
||||
from items i
|
||||
where i.guid = ?
|
||||
`, guid).Scan(
|
||||
&i.Id, &i.GUID, &i.FeedId, &i.Title, &i.Link, &i.Content,
|
||||
&i.Date, &i.Status, &i.ImageURL, &i.AudioURL,
|
||||
&i.Date, &i.Status, &i.MediaLinks,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
@@ -104,7 +104,7 @@ func TestListItems(t *testing.T) {
|
||||
|
||||
// filter by folder_id
|
||||
|
||||
have := getItemGuids(db.ListItems(ItemFilter{FolderID: &scope.folder1.Id}, 10, false))
|
||||
have := getItemGuids(db.ListItems(ItemFilter{FolderID: &scope.folder1.Id}, 10, false, false))
|
||||
want := []string{"item111", "item112", "item113", "item121", "item122"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -112,7 +112,7 @@ func TestListItems(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FolderID: &scope.folder2.Id}, 10, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FolderID: &scope.folder2.Id}, 10, false, false))
|
||||
want = []string{"item211", "item212"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -122,7 +122,7 @@ func TestListItems(t *testing.T) {
|
||||
|
||||
// filter by feed_id
|
||||
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FeedID: &scope.feed11.Id}, 10, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FeedID: &scope.feed11.Id}, 10, false, false))
|
||||
want = []string{"item111", "item112", "item113"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -130,7 +130,7 @@ func TestListItems(t *testing.T) {
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FeedID: &scope.feed01.Id}, 10, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{FeedID: &scope.feed01.Id}, 10, false, false))
|
||||
want = []string{"item011", "item012", "item013"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -141,7 +141,7 @@ func TestListItems(t *testing.T) {
|
||||
// filter by status
|
||||
|
||||
var starred ItemStatus = STARRED
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Status: &starred}, 10, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Status: &starred}, 10, false, false))
|
||||
want = []string{"item113", "item212", "item013"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -150,7 +150,7 @@ func TestListItems(t *testing.T) {
|
||||
}
|
||||
|
||||
var unread ItemStatus = UNREAD
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Status: &unread}, 10, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Status: &unread}, 10, false, false))
|
||||
want = []string{"item111", "item121", "item011"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -160,7 +160,7 @@ func TestListItems(t *testing.T) {
|
||||
|
||||
// limit
|
||||
|
||||
have = getItemGuids(db.ListItems(ItemFilter{}, 2, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{}, 2, false, false))
|
||||
want = []string{"item111", "item112"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -171,7 +171,7 @@ func TestListItems(t *testing.T) {
|
||||
// filter by search
|
||||
db.SyncSearch()
|
||||
search1 := "title111"
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Search: &search1}, 4, true))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{Search: &search1}, 4, true, false))
|
||||
want = []string{"item111"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -180,7 +180,7 @@ func TestListItems(t *testing.T) {
|
||||
}
|
||||
|
||||
// sort by date
|
||||
have = getItemGuids(db.ListItems(ItemFilter{}, 4, true))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{}, 4, true, false))
|
||||
want = []string{"item013", "item012", "item011", "item212"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -197,7 +197,7 @@ func TestListItemsPaginated(t *testing.T) {
|
||||
item121 := getItem(db, "item121")
|
||||
|
||||
// all, newest first
|
||||
have := getItemGuids(db.ListItems(ItemFilter{After: &item012.Id}, 3, true))
|
||||
have := getItemGuids(db.ListItems(ItemFilter{After: &item012.Id}, 3, true, false))
|
||||
want := []string{"item011", "item212", "item211"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -207,7 +207,7 @@ func TestListItemsPaginated(t *testing.T) {
|
||||
|
||||
// unread, newest first
|
||||
unread := UNREAD
|
||||
have = getItemGuids(db.ListItems(ItemFilter{After: &item012.Id, Status: &unread}, 3, true))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{After: &item012.Id, Status: &unread}, 3, true, false))
|
||||
want = []string{"item011", "item121", "item111"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -217,7 +217,7 @@ func TestListItemsPaginated(t *testing.T) {
|
||||
|
||||
// starred, oldest first
|
||||
starred := STARRED
|
||||
have = getItemGuids(db.ListItems(ItemFilter{After: &item121.Id, Status: &starred}, 3, false))
|
||||
have = getItemGuids(db.ListItems(ItemFilter{After: &item121.Id, Status: &starred}, 3, false, false))
|
||||
want = []string{"item212", "item013"}
|
||||
if !reflect.DeepEqual(have, want) {
|
||||
t.Logf("want: %#v", want)
|
||||
@@ -233,7 +233,7 @@ func TestMarkItemsRead(t *testing.T) {
|
||||
db1 := testDB()
|
||||
testItemsSetup(db1)
|
||||
db1.MarkItemsRead(MarkFilter{})
|
||||
have := getItemGuids(db1.ListItems(ItemFilter{Status: &read}, 10, false))
|
||||
have := getItemGuids(db1.ListItems(ItemFilter{Status: &read}, 10, false, false))
|
||||
want := []string{
|
||||
"item111", "item112", "item121", "item122",
|
||||
"item211", "item011", "item012",
|
||||
@@ -247,7 +247,7 @@ func TestMarkItemsRead(t *testing.T) {
|
||||
db2 := testDB()
|
||||
scope2 := testItemsSetup(db2)
|
||||
db2.MarkItemsRead(MarkFilter{FolderID: &scope2.folder1.Id})
|
||||
have = getItemGuids(db2.ListItems(ItemFilter{Status: &read}, 10, false))
|
||||
have = getItemGuids(db2.ListItems(ItemFilter{Status: &read}, 10, false, false))
|
||||
want = []string{
|
||||
"item111", "item112", "item121", "item122",
|
||||
"item211", "item012",
|
||||
@@ -261,7 +261,7 @@ func TestMarkItemsRead(t *testing.T) {
|
||||
db3 := testDB()
|
||||
scope3 := testItemsSetup(db3)
|
||||
db3.MarkItemsRead(MarkFilter{FeedID: &scope3.feed11.Id})
|
||||
have = getItemGuids(db3.ListItems(ItemFilter{Status: &read}, 10, false))
|
||||
have = getItemGuids(db3.ListItems(ItemFilter{Status: &read}, 10, false, false))
|
||||
want = []string{
|
||||
"item111", "item112", "item122",
|
||||
"item211", "item012",
|
||||
@@ -319,7 +319,7 @@ func TestDeleteOldItems(t *testing.T) {
|
||||
}
|
||||
|
||||
db.DeleteOldItems()
|
||||
feedItems := db.ListItems(ItemFilter{FeedID: &feed.Id}, 1000, false)
|
||||
feedItems := db.ListItems(ItemFilter{FeedID: &feed.Id}, 1000, false, false)
|
||||
if len(feedItems) != len(items)-3 {
|
||||
t.Fatalf(
|
||||
"invalid number of old items kept\nwant: %d\nhave: %d",
|
||||
|
||||
@@ -16,13 +16,17 @@ var migrations = []func(*sql.Tx) error{
|
||||
m06_fill_missing_dates,
|
||||
m07_add_feed_size,
|
||||
m08_normalize_datetime,
|
||||
m09_change_item_index,
|
||||
m10_add_item_medialinks,
|
||||
}
|
||||
|
||||
var maxVersion = int64(len(migrations))
|
||||
|
||||
func migrate(db *sql.DB) error {
|
||||
var version int64
|
||||
db.QueryRow("pragma user_version").Scan(&version)
|
||||
if err := db.QueryRow("pragma user_version").Scan(&version); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if version >= maxVersion {
|
||||
return nil
|
||||
@@ -294,3 +298,37 @@ func m08_normalize_datetime(tx *sql.Tx) error {
|
||||
_, err = tx.Exec(`update items set date = strftime('%Y-%m-%d %H:%M:%f', date);`)
|
||||
return err
|
||||
}
|
||||
|
||||
func m09_change_item_index(tx *sql.Tx) error {
|
||||
sql := `
|
||||
drop index if exists idx_item_status;
|
||||
create index if not exists idx_item__date_id_status on items(date,id,status);
|
||||
`
|
||||
_, err := tx.Exec(sql)
|
||||
return err
|
||||
}
|
||||
|
||||
func m10_add_item_medialinks(tx *sql.Tx) error {
|
||||
sql := `
|
||||
alter table items add column media_links blob;
|
||||
update items set media_links =
|
||||
iif(
|
||||
coalesce(image, '') != '' and coalesce(podcast_url, '') != '',
|
||||
json_array(json_object('type', 'image', 'url', image), json_object('type', 'audio', 'url', podcast_url)),
|
||||
iif(
|
||||
coalesce(image, '') != '',
|
||||
json_array(json_object('type', 'image', 'url', image)),
|
||||
iif(
|
||||
coalesce(podcast_url, '') != '',
|
||||
json_array(json_object('type', 'audio', 'url', podcast_url)),
|
||||
null
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
alter table items drop column image;
|
||||
alter table items drop column podcast_url;
|
||||
`
|
||||
_, err := tx.Exec(sql)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@ package storage
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
@@ -10,14 +13,17 @@ type Storage struct {
|
||||
}
|
||||
|
||||
func New(path string) (*Storage, error) {
|
||||
if pos := strings.IndexRune(path, '?'); pos == -1 {
|
||||
params := "_journal=WAL&_sync=NORMAL&_busy_timeout=5000&cache=shared"
|
||||
log.Printf("opening db with params: %s", params)
|
||||
path = path + "?" + params
|
||||
}
|
||||
|
||||
db, err := sql.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: https://foxcpp.dev/articles/the-right-way-to-use-go-sqlite3
|
||||
db.SetMaxOpenConns(1)
|
||||
|
||||
if err = migrate(db); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build darwin || windows
|
||||
// +build darwin windows
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build never
|
||||
// +build never
|
||||
|
||||
package systray
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build darwin
|
||||
// +build darwin
|
||||
|
||||
package systray
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package systray
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package systray
|
||||
|
||||
@@ -32,6 +32,10 @@ func (c *Client) getConditional(url, lastModified, etag string) (*http.Response,
|
||||
|
||||
var client *Client
|
||||
|
||||
func SetVersion(num string) {
|
||||
client.userAgent = "Yarr/" + num
|
||||
}
|
||||
|
||||
func init() {
|
||||
transport := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
|
||||
@@ -143,24 +143,19 @@ func ConvertItems(items []parser.Item, feed storage.Feed) []storage.Item {
|
||||
result := make([]storage.Item, len(items))
|
||||
for i, item := range items {
|
||||
item := item
|
||||
var audioURL *string = nil
|
||||
if item.AudioURL != "" {
|
||||
audioURL = &item.AudioURL
|
||||
}
|
||||
var imageURL *string = nil
|
||||
if item.ImageURL != "" {
|
||||
imageURL = &item.ImageURL
|
||||
mediaLinks := make(storage.MediaLinks, 0)
|
||||
for _, link := range item.MediaLinks {
|
||||
mediaLinks = append(mediaLinks, storage.MediaLink(link))
|
||||
}
|
||||
result[i] = storage.Item{
|
||||
GUID: item.GUID,
|
||||
FeedId: feed.Id,
|
||||
Title: item.Title,
|
||||
Link: item.URL,
|
||||
Content: item.Content,
|
||||
Date: item.Date,
|
||||
Status: storage.UNREAD,
|
||||
ImageURL: imageURL,
|
||||
AudioURL: audioURL,
|
||||
GUID: item.GUID,
|
||||
FeedId: feed.Id,
|
||||
Title: item.Title,
|
||||
Link: item.URL,
|
||||
Content: item.Content,
|
||||
Date: item.Date,
|
||||
Status: storage.UNREAD,
|
||||
MediaLinks: mediaLinks,
|
||||
}
|
||||
}
|
||||
return result
|
||||
|
||||
4
vendor/golang.org/x/net/LICENSE
generated
vendored
4
vendor/golang.org/x/net/LICENSE
generated
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
27
vendor/golang.org/x/net/html/doc.go
generated
vendored
27
vendor/golang.org/x/net/html/doc.go
generated
vendored
@@ -78,16 +78,11 @@ example, to process each anchor node in depth-first order:
|
||||
if err != nil {
|
||||
// ...
|
||||
}
|
||||
var f func(*html.Node)
|
||||
f = func(n *html.Node) {
|
||||
for n := range doc.Descendants() {
|
||||
if n.Type == html.ElementNode && n.Data == "a" {
|
||||
// Do something with n...
|
||||
}
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
f(c)
|
||||
}
|
||||
}
|
||||
f(doc)
|
||||
|
||||
The relevant specifications include:
|
||||
https://html.spec.whatwg.org/multipage/syntax.html and
|
||||
@@ -99,14 +94,20 @@ Care should be taken when parsing and interpreting HTML, whether full documents
|
||||
or fragments, within the framework of the HTML specification, especially with
|
||||
regard to untrusted inputs.
|
||||
|
||||
This package provides both a tokenizer and a parser. Only the parser constructs
|
||||
a DOM according to the HTML specification, resolving malformed and misplaced
|
||||
tags where appropriate. The tokenizer simply tokenizes the HTML presented to it,
|
||||
and as such does not resolve issues that may exist in the processed HTML,
|
||||
producing a literal interpretation of the input.
|
||||
This package provides both a tokenizer and a parser, which implement the
|
||||
tokenization, and tokenization and tree construction stages of the WHATWG HTML
|
||||
parsing specification respectively. While the tokenizer parses and normalizes
|
||||
individual HTML tokens, only the parser constructs the DOM tree from the
|
||||
tokenized HTML, as described in the tree construction stage of the
|
||||
specification, dynamically modifying or extending the document's DOM tree.
|
||||
|
||||
If your use case requires semantically well-formed HTML, as defined by the
|
||||
WHATWG specifiction, the parser should be used rather than the tokenizer.
|
||||
If your use case requires semantically well-formed HTML documents, as defined by
|
||||
the WHATWG specification, the parser should be used rather than the tokenizer.
|
||||
|
||||
In security contexts, if trust decisions are being made using the tokenized or
|
||||
parsed content, the input must be re-serialized (for instance by using Render or
|
||||
Token.String) in order for those trust decisions to hold, as the process of
|
||||
tokenization or parsing may alter the content.
|
||||
*/
|
||||
package html // import "golang.org/x/net/html"
|
||||
|
||||
|
||||
2
vendor/golang.org/x/net/html/doctype.go
generated
vendored
2
vendor/golang.org/x/net/html/doctype.go
generated
vendored
@@ -87,7 +87,7 @@ func parseDoctype(s string) (n *Node, quirks bool) {
|
||||
}
|
||||
}
|
||||
if lastAttr := n.Attr[len(n.Attr)-1]; lastAttr.Key == "system" &&
|
||||
strings.ToLower(lastAttr.Val) == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" {
|
||||
strings.EqualFold(lastAttr.Val, "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd") {
|
||||
quirks = true
|
||||
}
|
||||
}
|
||||
|
||||
3
vendor/golang.org/x/net/html/foreign.go
generated
vendored
3
vendor/golang.org/x/net/html/foreign.go
generated
vendored
@@ -40,8 +40,7 @@ func htmlIntegrationPoint(n *Node) bool {
|
||||
if n.Data == "annotation-xml" {
|
||||
for _, a := range n.Attr {
|
||||
if a.Key == "encoding" {
|
||||
val := strings.ToLower(a.Val)
|
||||
if val == "text/html" || val == "application/xhtml+xml" {
|
||||
if strings.EqualFold(a.Val, "text/html") || strings.EqualFold(a.Val, "application/xhtml+xml") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
56
vendor/golang.org/x/net/html/iter.go
generated
vendored
Normal file
56
vendor/golang.org/x/net/html/iter.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build go1.23
|
||||
|
||||
package html
|
||||
|
||||
import "iter"
|
||||
|
||||
// Ancestors returns an iterator over the ancestors of n, starting with n.Parent.
|
||||
//
|
||||
// Mutating a Node or its parents while iterating may have unexpected results.
|
||||
func (n *Node) Ancestors() iter.Seq[*Node] {
|
||||
_ = n.Parent // eager nil check
|
||||
|
||||
return func(yield func(*Node) bool) {
|
||||
for p := n.Parent; p != nil && yield(p); p = p.Parent {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ChildNodes returns an iterator over the immediate children of n,
|
||||
// starting with n.FirstChild.
|
||||
//
|
||||
// Mutating a Node or its children while iterating may have unexpected results.
|
||||
func (n *Node) ChildNodes() iter.Seq[*Node] {
|
||||
_ = n.FirstChild // eager nil check
|
||||
|
||||
return func(yield func(*Node) bool) {
|
||||
for c := n.FirstChild; c != nil && yield(c); c = c.NextSibling {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Descendants returns an iterator over all nodes recursively beneath
|
||||
// n, excluding n itself. Nodes are visited in depth-first preorder.
|
||||
//
|
||||
// Mutating a Node or its descendants while iterating may have unexpected results.
|
||||
func (n *Node) Descendants() iter.Seq[*Node] {
|
||||
_ = n.FirstChild // eager nil check
|
||||
|
||||
return func(yield func(*Node) bool) {
|
||||
n.descendants(yield)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) descendants(yield func(*Node) bool) bool {
|
||||
for c := range n.ChildNodes() {
|
||||
if !yield(c) || !c.descendants(yield) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
4
vendor/golang.org/x/net/html/node.go
generated
vendored
4
vendor/golang.org/x/net/html/node.go
generated
vendored
@@ -38,6 +38,10 @@ var scopeMarker = Node{Type: scopeMarkerNode}
|
||||
// that it looks like "a<b" rather than "a<b". For element nodes, DataAtom
|
||||
// is the atom for Data, or zero if Data is not a known tag name.
|
||||
//
|
||||
// Node trees may be navigated using the link fields (Parent,
|
||||
// FirstChild, and so on) or a range loop over iterators such as
|
||||
// [Node.Descendants].
|
||||
//
|
||||
// An empty Namespace implies a "http://www.w3.org/1999/xhtml" namespace.
|
||||
// Similarly, "math" is short for "http://www.w3.org/1998/Math/MathML", and
|
||||
// "svg" is short for "http://www.w3.org/2000/svg".
|
||||
|
||||
8
vendor/golang.org/x/net/html/parse.go
generated
vendored
8
vendor/golang.org/x/net/html/parse.go
generated
vendored
@@ -840,6 +840,10 @@ func afterHeadIM(p *parser) bool {
|
||||
|
||||
p.parseImpliedToken(StartTagToken, a.Body, a.Body.String())
|
||||
p.framesetOK = true
|
||||
if p.tok.Type == ErrorToken {
|
||||
// Stop parsing.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1031,7 +1035,7 @@ func inBodyIM(p *parser) bool {
|
||||
if p.tok.DataAtom == a.Input {
|
||||
for _, t := range p.tok.Attr {
|
||||
if t.Key == "type" {
|
||||
if strings.ToLower(t.Val) == "hidden" {
|
||||
if strings.EqualFold(t.Val, "hidden") {
|
||||
// Skip setting framesetOK = false
|
||||
return true
|
||||
}
|
||||
@@ -1459,7 +1463,7 @@ func inTableIM(p *parser) bool {
|
||||
return inHeadIM(p)
|
||||
case a.Input:
|
||||
for _, t := range p.tok.Attr {
|
||||
if t.Key == "type" && strings.ToLower(t.Val) == "hidden" {
|
||||
if t.Key == "type" && strings.EqualFold(t.Val, "hidden") {
|
||||
p.addElement()
|
||||
p.oe.pop()
|
||||
return true
|
||||
|
||||
28
vendor/golang.org/x/net/html/render.go
generated
vendored
28
vendor/golang.org/x/net/html/render.go
generated
vendored
@@ -194,9 +194,8 @@ func render1(w writer, n *Node) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Render any child nodes.
|
||||
switch n.Data {
|
||||
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||
// Render any child nodes
|
||||
if childTextNodesAreLiteral(n) {
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if c.Type == TextNode {
|
||||
if _, err := w.WriteString(c.Data); err != nil {
|
||||
@@ -213,7 +212,7 @@ func render1(w writer, n *Node) error {
|
||||
// last element in the file, with no closing tag.
|
||||
return plaintextAbort
|
||||
}
|
||||
default:
|
||||
} else {
|
||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
||||
if err := render1(w, c); err != nil {
|
||||
return err
|
||||
@@ -231,6 +230,27 @@ func render1(w writer, n *Node) error {
|
||||
return w.WriteByte('>')
|
||||
}
|
||||
|
||||
func childTextNodesAreLiteral(n *Node) bool {
|
||||
// Per WHATWG HTML 13.3, if the parent of the current node is a style,
|
||||
// script, xmp, iframe, noembed, noframes, or plaintext element, and the
|
||||
// current node is a text node, append the value of the node's data
|
||||
// literally. The specification is not explicit about it, but we only
|
||||
// enforce this if we are in the HTML namespace (i.e. when the namespace is
|
||||
// "").
|
||||
// NOTE: we also always include noscript elements, although the
|
||||
// specification states that they should only be rendered as such if
|
||||
// scripting is enabled for the node (which is not something we track).
|
||||
if n.Namespace != "" {
|
||||
return false
|
||||
}
|
||||
switch n.Data {
|
||||
case "iframe", "noembed", "noframes", "noscript", "plaintext", "script", "style", "xmp":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// writeQuoted writes s to w surrounded by quotes. Normally it will use double
|
||||
// quotes, but if s contains a double quote, it will use single quotes.
|
||||
// It is used for writing the identifiers in a doctype declaration.
|
||||
|
||||
19
vendor/golang.org/x/net/html/token.go
generated
vendored
19
vendor/golang.org/x/net/html/token.go
generated
vendored
@@ -910,10 +910,16 @@ func (z *Tokenizer) readTagAttrKey() {
|
||||
return
|
||||
}
|
||||
switch c {
|
||||
case ' ', '\n', '\r', '\t', '\f', '/':
|
||||
z.pendingAttr[0].end = z.raw.end - 1
|
||||
return
|
||||
case '=', '>':
|
||||
case '=':
|
||||
if z.pendingAttr[0].start+1 == z.raw.end {
|
||||
// WHATWG 13.2.5.32, if we see an equals sign before the attribute name
|
||||
// begins, we treat it as a character in the attribute name and continue.
|
||||
continue
|
||||
}
|
||||
fallthrough
|
||||
case ' ', '\n', '\r', '\t', '\f', '/', '>':
|
||||
// WHATWG 13.2.5.33 Attribute name state
|
||||
// We need to reconsume the char in the after attribute name state to support the / character
|
||||
z.raw.end--
|
||||
z.pendingAttr[0].end = z.raw.end
|
||||
return
|
||||
@@ -932,6 +938,11 @@ func (z *Tokenizer) readTagAttrVal() {
|
||||
if z.err != nil {
|
||||
return
|
||||
}
|
||||
if c == '/' {
|
||||
// WHATWG 13.2.5.34 After attribute name state
|
||||
// U+002F SOLIDUS (/) - Switch to the self-closing start tag state.
|
||||
return
|
||||
}
|
||||
if c != '=' {
|
||||
z.raw.end--
|
||||
return
|
||||
|
||||
4
vendor/golang.org/x/sys/LICENSE
generated
vendored
4
vendor/golang.org/x/sys/LICENSE
generated
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
30
vendor/golang.org/x/sys/internal/unsafeheader/unsafeheader.go
generated
vendored
30
vendor/golang.org/x/sys/internal/unsafeheader/unsafeheader.go
generated
vendored
@@ -1,30 +0,0 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package unsafeheader contains header declarations for the Go runtime's
|
||||
// slice and string implementations.
|
||||
//
|
||||
// This package allows x/sys to use types equivalent to
|
||||
// reflect.SliceHeader and reflect.StringHeader without introducing
|
||||
// a dependency on the (relatively heavy) "reflect" package.
|
||||
package unsafeheader
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Slice is the runtime representation of a slice.
|
||||
// It cannot be used safely or portably and its representation may change in a later release.
|
||||
type Slice struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
Cap int
|
||||
}
|
||||
|
||||
// String is the runtime representation of a string.
|
||||
// It cannot be used safely or portably and its representation may change in a later release.
|
||||
type String struct {
|
||||
Data unsafe.Pointer
|
||||
Len int
|
||||
}
|
||||
3
vendor/golang.org/x/sys/windows/aliases.go
generated
vendored
3
vendor/golang.org/x/sys/windows/aliases.go
generated
vendored
@@ -2,8 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows && go1.9
|
||||
// +build windows,go1.9
|
||||
//go:build windows
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
2
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
2
vendor/golang.org/x/sys/windows/dll_windows.go
generated
vendored
@@ -65,7 +65,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation failes.
|
||||
// MustLoadDLL is like LoadDLL but panics if load operation fails.
|
||||
func MustLoadDLL(name string) *DLL {
|
||||
d, e := LoadDLL(name)
|
||||
if e != nil {
|
||||
|
||||
9
vendor/golang.org/x/sys/windows/empty.s
generated
vendored
9
vendor/golang.org/x/sys/windows/empty.s
generated
vendored
@@ -1,9 +0,0 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !go1.12
|
||||
// +build !go1.12
|
||||
|
||||
// This file is here to allow bodyless functions with go:linkname for Go 1.11
|
||||
// and earlier (see https://golang.org/issue/23311).
|
||||
17
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
17
vendor/golang.org/x/sys/windows/env_windows.go
generated
vendored
@@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) {
|
||||
return nil, err
|
||||
}
|
||||
defer DestroyEnvironmentBlock(block)
|
||||
blockp := uintptr(unsafe.Pointer(block))
|
||||
for {
|
||||
entry := UTF16PtrToString((*uint16)(unsafe.Pointer(blockp)))
|
||||
if len(entry) == 0 {
|
||||
break
|
||||
size := unsafe.Sizeof(*block)
|
||||
for *block != 0 {
|
||||
// find NUL terminator
|
||||
end := unsafe.Pointer(block)
|
||||
for *(*uint16)(end) != 0 {
|
||||
end = unsafe.Add(end, size)
|
||||
}
|
||||
env = append(env, entry)
|
||||
blockp += 2 * (uintptr(len(entry)) + 1)
|
||||
|
||||
entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size)
|
||||
env = append(env, UTF16ToString(entry))
|
||||
block = (*uint16)(unsafe.Add(end, size))
|
||||
}
|
||||
return env, nil
|
||||
}
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
1
vendor/golang.org/x/sys/windows/eventlog.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
94
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
94
vendor/golang.org/x/sys/windows/exec_windows.go
generated
vendored
@@ -22,7 +22,7 @@ import (
|
||||
// but only if there is space or tab inside s.
|
||||
func EscapeArg(s string) string {
|
||||
if len(s) == 0 {
|
||||
return "\"\""
|
||||
return `""`
|
||||
}
|
||||
n := len(s)
|
||||
hasSpace := false
|
||||
@@ -35,7 +35,7 @@ func EscapeArg(s string) string {
|
||||
}
|
||||
}
|
||||
if hasSpace {
|
||||
n += 2
|
||||
n += 2 // Reserve space for quotes.
|
||||
}
|
||||
if n == len(s) {
|
||||
return s
|
||||
@@ -82,36 +82,106 @@ func EscapeArg(s string) string {
|
||||
// in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument,
|
||||
// or any program that uses CommandLineToArgv.
|
||||
func ComposeCommandLine(args []string) string {
|
||||
var commandLine string
|
||||
for i := range args {
|
||||
if i > 0 {
|
||||
commandLine += " "
|
||||
}
|
||||
commandLine += EscapeArg(args[i])
|
||||
if len(args) == 0 {
|
||||
return ""
|
||||
}
|
||||
return commandLine
|
||||
|
||||
// Per https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw:
|
||||
// “This function accepts command lines that contain a program name; the
|
||||
// program name can be enclosed in quotation marks or not.”
|
||||
//
|
||||
// Unfortunately, it provides no means of escaping interior quotation marks
|
||||
// within that program name, and we have no way to report them here.
|
||||
prog := args[0]
|
||||
mustQuote := len(prog) == 0
|
||||
for i := 0; i < len(prog); i++ {
|
||||
c := prog[i]
|
||||
if c <= ' ' || (c == '"' && i == 0) {
|
||||
// Force quotes for not only the ASCII space and tab as described in the
|
||||
// MSDN article, but also ASCII control characters.
|
||||
// The documentation for CommandLineToArgvW doesn't say what happens when
|
||||
// the first argument is not a valid program name, but it empirically
|
||||
// seems to drop unquoted control characters.
|
||||
mustQuote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
var commandLine []byte
|
||||
if mustQuote {
|
||||
commandLine = make([]byte, 0, len(prog)+2)
|
||||
commandLine = append(commandLine, '"')
|
||||
for i := 0; i < len(prog); i++ {
|
||||
c := prog[i]
|
||||
if c == '"' {
|
||||
// This quote would interfere with our surrounding quotes.
|
||||
// We have no way to report an error, so just strip out
|
||||
// the offending character instead.
|
||||
continue
|
||||
}
|
||||
commandLine = append(commandLine, c)
|
||||
}
|
||||
commandLine = append(commandLine, '"')
|
||||
} else {
|
||||
if len(args) == 1 {
|
||||
// args[0] is a valid command line representing itself.
|
||||
// No need to allocate a new slice or string for it.
|
||||
return prog
|
||||
}
|
||||
commandLine = []byte(prog)
|
||||
}
|
||||
|
||||
for _, arg := range args[1:] {
|
||||
commandLine = append(commandLine, ' ')
|
||||
// TODO(bcmills): since we're already appending to a slice, it would be nice
|
||||
// to avoid the intermediate allocations of EscapeArg.
|
||||
// Perhaps we can factor out an appendEscapedArg function.
|
||||
commandLine = append(commandLine, EscapeArg(arg)...)
|
||||
}
|
||||
return string(commandLine)
|
||||
}
|
||||
|
||||
// DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv,
|
||||
// as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that
|
||||
// command lines are passed around.
|
||||
// DecomposeCommandLine returns an error if commandLine contains NUL.
|
||||
func DecomposeCommandLine(commandLine string) ([]string, error) {
|
||||
if len(commandLine) == 0 {
|
||||
return []string{}, nil
|
||||
}
|
||||
utf16CommandLine, err := UTF16FromString(commandLine)
|
||||
if err != nil {
|
||||
return nil, errorspkg.New("string with NUL passed to DecomposeCommandLine")
|
||||
}
|
||||
var argc int32
|
||||
argv, err := CommandLineToArgv(StringToUTF16Ptr(commandLine), &argc)
|
||||
argv, err := commandLineToArgv(&utf16CommandLine[0], &argc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer LocalFree(Handle(unsafe.Pointer(argv)))
|
||||
|
||||
var args []string
|
||||
for _, v := range (*argv)[:argc] {
|
||||
args = append(args, UTF16ToString((*v)[:]))
|
||||
for _, p := range unsafe.Slice(argv, argc) {
|
||||
args = append(args, UTF16PtrToString(p))
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// CommandLineToArgv parses a Unicode command line string and sets
|
||||
// argc to the number of parsed arguments.
|
||||
//
|
||||
// The returned memory should be freed using a single call to LocalFree.
|
||||
//
|
||||
// Note that although the return type of CommandLineToArgv indicates 8192
|
||||
// entries of up to 8192 characters each, the actual count of parsed arguments
|
||||
// may exceed 8192, and the documentation for CommandLineToArgvW does not mention
|
||||
// any bound on the lengths of the individual argument strings.
|
||||
// (See https://go.dev/issue/63236.)
|
||||
func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
|
||||
argp, err := commandLineToArgv(cmd, argc)
|
||||
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(argp))
|
||||
return argv, err
|
||||
}
|
||||
|
||||
func CloseOnExec(fd Handle) {
|
||||
SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0)
|
||||
}
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/mksyscall.go
generated
vendored
1
vendor/golang.org/x/sys/windows/mksyscall.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build generate
|
||||
// +build generate
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/race.go
generated
vendored
1
vendor/golang.org/x/sys/windows/race.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows && race
|
||||
// +build windows,race
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
1
vendor/golang.org/x/sys/windows/race0.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows && !race
|
||||
// +build windows,!race
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
46
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
46
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
@@ -7,8 +7,6 @@ package windows
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/internal/unsafeheader"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -70,6 +68,7 @@ type UserInfo10 struct {
|
||||
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
|
||||
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
|
||||
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
|
||||
//sys NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) = netapi32.NetUserEnum
|
||||
|
||||
const (
|
||||
// do not reorder
|
||||
@@ -895,7 +894,7 @@ type ACL struct {
|
||||
aclRevision byte
|
||||
sbz1 byte
|
||||
aclSize uint16
|
||||
aceCount uint16
|
||||
AceCount uint16
|
||||
sbz2 uint16
|
||||
}
|
||||
|
||||
@@ -1088,6 +1087,27 @@ type EXPLICIT_ACCESS struct {
|
||||
Trustee TRUSTEE
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
|
||||
type ACE_HEADER struct {
|
||||
AceType uint8
|
||||
AceFlags uint8
|
||||
AceSize uint16
|
||||
}
|
||||
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-access_allowed_ace
|
||||
type ACCESS_ALLOWED_ACE struct {
|
||||
Header ACE_HEADER
|
||||
Mask ACCESS_MASK
|
||||
SidStart uint32
|
||||
}
|
||||
|
||||
const (
|
||||
// Constants for AceType
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-ace_header
|
||||
ACCESS_ALLOWED_ACE_TYPE = 0
|
||||
ACCESS_DENIED_ACE_TYPE = 1
|
||||
)
|
||||
|
||||
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
|
||||
type TrusteeValue uintptr
|
||||
|
||||
@@ -1159,6 +1179,7 @@ type OBJECTS_AND_NAME struct {
|
||||
//sys makeSelfRelativeSD(absoluteSD *SECURITY_DESCRIPTOR, selfRelativeSD *SECURITY_DESCRIPTOR, selfRelativeSDSize *uint32) (err error) = advapi32.MakeSelfRelativeSD
|
||||
|
||||
//sys setEntriesInAcl(countExplicitEntries uint32, explicitEntries *EXPLICIT_ACCESS, oldACL *ACL, newACL **ACL) (ret error) = advapi32.SetEntriesInAclW
|
||||
//sys GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) = advapi32.GetAce
|
||||
|
||||
// Control returns the security descriptor control bits.
|
||||
func (sd *SECURITY_DESCRIPTOR) Control() (control SECURITY_DESCRIPTOR_CONTROL, revision uint32, err error) {
|
||||
@@ -1341,21 +1362,14 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) copySelfRelativeSecurityDescriptor()
|
||||
sdLen = min
|
||||
}
|
||||
|
||||
var src []byte
|
||||
h := (*unsafeheader.Slice)(unsafe.Pointer(&src))
|
||||
h.Data = unsafe.Pointer(selfRelativeSD)
|
||||
h.Len = sdLen
|
||||
h.Cap = sdLen
|
||||
|
||||
src := unsafe.Slice((*byte)(unsafe.Pointer(selfRelativeSD)), sdLen)
|
||||
// SECURITY_DESCRIPTOR has pointers in it, which means checkptr expects for it to
|
||||
// be aligned properly. When we're copying a Windows-allocated struct to a
|
||||
// Go-allocated one, make sure that the Go allocation is aligned to the
|
||||
// pointer size.
|
||||
const psize = int(unsafe.Sizeof(uintptr(0)))
|
||||
|
||||
var dst []byte
|
||||
h = (*unsafeheader.Slice)(unsafe.Pointer(&dst))
|
||||
alloc := make([]uintptr, (sdLen+psize-1)/psize)
|
||||
h.Data = (*unsafeheader.Slice)(unsafe.Pointer(&alloc)).Data
|
||||
h.Len = sdLen
|
||||
h.Cap = sdLen
|
||||
|
||||
dst := unsafe.Slice((*byte)(unsafe.Pointer(&alloc[0])), sdLen)
|
||||
copy(dst, src)
|
||||
return (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&dst[0]))
|
||||
}
|
||||
|
||||
12
vendor/golang.org/x/sys/windows/service.go
generated
vendored
12
vendor/golang.org/x/sys/windows/service.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
@@ -141,6 +140,12 @@ const (
|
||||
SERVICE_DYNAMIC_INFORMATION_LEVEL_START_REASON = 1
|
||||
)
|
||||
|
||||
type ENUM_SERVICE_STATUS struct {
|
||||
ServiceName *uint16
|
||||
DisplayName *uint16
|
||||
ServiceStatus SERVICE_STATUS
|
||||
}
|
||||
|
||||
type SERVICE_STATUS struct {
|
||||
ServiceType uint32
|
||||
CurrentState uint32
|
||||
@@ -212,6 +217,10 @@ type SERVICE_FAILURE_ACTIONS struct {
|
||||
Actions *SC_ACTION
|
||||
}
|
||||
|
||||
type SERVICE_FAILURE_ACTIONS_FLAG struct {
|
||||
FailureActionsOnNonCrashFailures int32
|
||||
}
|
||||
|
||||
type SC_ACTION struct {
|
||||
Type uint32
|
||||
Delay uint32
|
||||
@@ -245,3 +254,4 @@ type QUERY_SERVICE_LOCK_STATUS struct {
|
||||
//sys UnsubscribeServiceChangeNotifications(subscription uintptr) = sechost.UnsubscribeServiceChangeNotifications?
|
||||
//sys RegisterServiceCtrlHandlerEx(serviceName *uint16, handlerProc uintptr, context uintptr) (handle Handle, err error) = advapi32.RegisterServiceCtrlHandlerExW
|
||||
//sys QueryServiceDynamicInformation(service Handle, infoLevel uint32, dynamicInfo unsafe.Pointer) (err error) = advapi32.QueryServiceDynamicInformation?
|
||||
//sys EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) = advapi32.EnumDependentServicesW
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/str.go
generated
vendored
1
vendor/golang.org/x/sys/windows/str.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
package windows
|
||||
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
1
vendor/golang.org/x/sys/windows/syscall.go
generated
vendored
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build windows
|
||||
// +build windows
|
||||
|
||||
// Package windows contains an interface to the low-level operating system
|
||||
// primitives. OS details vary depending on the underlying system, and
|
||||
|
||||
214
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
214
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
@@ -15,12 +15,12 @@ import (
|
||||
"time"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/internal/unsafeheader"
|
||||
)
|
||||
|
||||
type Handle uintptr
|
||||
type HWND uintptr
|
||||
type (
|
||||
Handle uintptr
|
||||
HWND uintptr
|
||||
)
|
||||
|
||||
const (
|
||||
InvalidHandle = ^Handle(0)
|
||||
@@ -127,22 +127,21 @@ func UTF16PtrToString(p *uint16) string {
|
||||
for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ {
|
||||
ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p))
|
||||
}
|
||||
|
||||
return string(utf16.Decode(unsafe.Slice(p, n)))
|
||||
return UTF16ToString(unsafe.Slice(p, n))
|
||||
}
|
||||
|
||||
func Getpagesize() int { return 4096 }
|
||||
|
||||
// NewCallback converts a Go function to a function pointer conforming to the stdcall calling convention.
|
||||
// This is useful when interoperating with Windows code requiring callbacks.
|
||||
// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
|
||||
// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
|
||||
func NewCallback(fn interface{}) uintptr {
|
||||
return syscall.NewCallback(fn)
|
||||
}
|
||||
|
||||
// NewCallbackCDecl converts a Go function to a function pointer conforming to the cdecl calling convention.
|
||||
// This is useful when interoperating with Windows code requiring callbacks.
|
||||
// The argument is expected to be a function with with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
|
||||
// The argument is expected to be a function with one uintptr-sized result. The function must not have arguments with size larger than the size of uintptr.
|
||||
func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
return syscall.NewCallbackCDecl(fn)
|
||||
}
|
||||
@@ -157,6 +156,8 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys GetModuleFileName(module Handle, filename *uint16, size uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
|
||||
//sys GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err error) = kernel32.GetModuleHandleExW
|
||||
//sys SetDefaultDllDirectories(directoryFlags uint32) (err error)
|
||||
//sys AddDllDirectory(path *uint16) (cookie uintptr, err error) = kernel32.AddDllDirectory
|
||||
//sys RemoveDllDirectory(cookie uintptr) (err error) = kernel32.RemoveDllDirectory
|
||||
//sys SetDllDirectory(path string) (err error) = kernel32.SetDllDirectoryW
|
||||
//sys GetVersion() (ver uint32, err error)
|
||||
//sys FormatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
|
||||
@@ -166,6 +167,9 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile Handle) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
|
||||
//sys CreateNamedPipe(name *uint16, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *SecurityAttributes) (handle Handle, err error) [failretval==InvalidHandle] = CreateNamedPipeW
|
||||
//sys ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error)
|
||||
//sys DisconnectNamedPipe(pipe Handle) (err error)
|
||||
//sys GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error)
|
||||
//sys GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error)
|
||||
//sys GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error)
|
||||
//sys GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
|
||||
//sys SetNamedPipeHandleState(pipe Handle, state *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32) (err error) = SetNamedPipeHandleState
|
||||
@@ -194,6 +198,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
|
||||
//sys GetComputerNameEx(nametype uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
|
||||
//sys SetEndOfFile(handle Handle) (err error)
|
||||
//sys SetFileValidData(handle Handle, validDataLength int64) (err error)
|
||||
//sys GetSystemTimeAsFileTime(time *Filetime)
|
||||
//sys GetSystemTimePreciseAsFileTime(time *Filetime)
|
||||
//sys GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
|
||||
@@ -210,13 +215,17 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys OpenProcess(desiredAccess uint32, inheritHandle bool, processId uint32) (handle Handle, err error)
|
||||
//sys ShellExecute(hwnd Handle, verb *uint16, file *uint16, args *uint16, cwd *uint16, showCmd int32) (err error) [failretval<=32] = shell32.ShellExecuteW
|
||||
//sys GetWindowThreadProcessId(hwnd HWND, pid *uint32) (tid uint32, err error) = user32.GetWindowThreadProcessId
|
||||
//sys LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) [failretval==0] = user32.LoadKeyboardLayoutW
|
||||
//sys UnloadKeyboardLayout(hkl Handle) (err error) = user32.UnloadKeyboardLayout
|
||||
//sys GetKeyboardLayout(tid uint32) (hkl Handle) = user32.GetKeyboardLayout
|
||||
//sys ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) = user32.ToUnicodeEx
|
||||
//sys GetShellWindow() (shellWindow HWND) = user32.GetShellWindow
|
||||
//sys MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) [failretval==0] = user32.MessageBoxW
|
||||
//sys ExitWindowsEx(flags uint32, reason uint32) (err error) = user32.ExitWindowsEx
|
||||
//sys shGetKnownFolderPath(id *KNOWNFOLDERID, flags uint32, token Token, path **uint16) (ret error) = shell32.SHGetKnownFolderPath
|
||||
//sys TerminateProcess(handle Handle, exitcode uint32) (err error)
|
||||
//sys GetExitCodeProcess(handle Handle, exitcode *uint32) (err error)
|
||||
//sys GetStartupInfo(startupInfo *StartupInfo) (err error) = GetStartupInfoW
|
||||
//sys getStartupInfo(startupInfo *StartupInfo) = GetStartupInfoW
|
||||
//sys GetProcessTimes(handle Handle, creationTime *Filetime, exitTime *Filetime, kernelTime *Filetime, userTime *Filetime) (err error)
|
||||
//sys DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error)
|
||||
//sys WaitForSingleObject(handle Handle, waitMilliseconds uint32) (event uint32, err error) [failretval==0xffffffff]
|
||||
@@ -235,12 +244,13 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) = userenv.CreateEnvironmentBlock
|
||||
//sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock
|
||||
//sys getTickCount64() (ms uint64) = kernel32.GetTickCount64
|
||||
//sys GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
|
||||
//sys SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error)
|
||||
//sys GetFileAttributes(name *uint16) (attrs uint32, err error) [failretval==INVALID_FILE_ATTRIBUTES] = kernel32.GetFileAttributesW
|
||||
//sys SetFileAttributes(name *uint16, attrs uint32) (err error) = kernel32.SetFileAttributesW
|
||||
//sys GetFileAttributesEx(name *uint16, level uint32, info *byte) (err error) = kernel32.GetFileAttributesExW
|
||||
//sys GetCommandLine() (cmd *uint16) = kernel32.GetCommandLineW
|
||||
//sys CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
|
||||
//sys commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) [failretval==nil] = shell32.CommandLineToArgvW
|
||||
//sys LocalFree(hmem Handle) (handle Handle, err error) [failretval!=0]
|
||||
//sys LocalAlloc(flags uint32, length uint32) (ptr uintptr, err error)
|
||||
//sys SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error)
|
||||
@@ -299,12 +309,19 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys RegNotifyChangeKeyValue(key Handle, watchSubtree bool, notifyFilter uint32, event Handle, asynchronous bool) (regerrno error) = advapi32.RegNotifyChangeKeyValue
|
||||
//sys GetCurrentProcessId() (pid uint32) = kernel32.GetCurrentProcessId
|
||||
//sys ProcessIdToSessionId(pid uint32, sessionid *uint32) (err error) = kernel32.ProcessIdToSessionId
|
||||
//sys ClosePseudoConsole(console Handle) = kernel32.ClosePseudoConsole
|
||||
//sys createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pconsole *Handle) (hr error) = kernel32.CreatePseudoConsole
|
||||
//sys GetConsoleMode(console Handle, mode *uint32) (err error) = kernel32.GetConsoleMode
|
||||
//sys SetConsoleMode(console Handle, mode uint32) (err error) = kernel32.SetConsoleMode
|
||||
//sys GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) = kernel32.GetConsoleScreenBufferInfo
|
||||
//sys setConsoleCursorPosition(console Handle, position uint32) (err error) = kernel32.SetConsoleCursorPosition
|
||||
//sys GetConsoleCP() (cp uint32, err error) = kernel32.GetConsoleCP
|
||||
//sys GetConsoleOutputCP() (cp uint32, err error) = kernel32.GetConsoleOutputCP
|
||||
//sys SetConsoleCP(cp uint32) (err error) = kernel32.SetConsoleCP
|
||||
//sys SetConsoleOutputCP(cp uint32) (err error) = kernel32.SetConsoleOutputCP
|
||||
//sys WriteConsole(console Handle, buf *uint16, towrite uint32, written *uint32, reserved *byte) (err error) = kernel32.WriteConsoleW
|
||||
//sys ReadConsole(console Handle, buf *uint16, toread uint32, read *uint32, inputControl *byte) (err error) = kernel32.ReadConsoleW
|
||||
//sys resizePseudoConsole(pconsole Handle, size uint32) (hr error) = kernel32.ResizePseudoConsole
|
||||
//sys CreateToolhelp32Snapshot(flags uint32, processId uint32) (handle Handle, err error) [failretval==InvalidHandle] = kernel32.CreateToolhelp32Snapshot
|
||||
//sys Module32First(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32FirstW
|
||||
//sys Module32Next(snapshot Handle, moduleEntry *ModuleEntry32) (err error) = kernel32.Module32NextW
|
||||
@@ -344,8 +361,19 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys SetProcessPriorityBoost(process Handle, disable bool) (err error) = kernel32.SetProcessPriorityBoost
|
||||
//sys GetProcessWorkingSetSizeEx(hProcess Handle, lpMinimumWorkingSetSize *uintptr, lpMaximumWorkingSetSize *uintptr, flags *uint32)
|
||||
//sys SetProcessWorkingSetSizeEx(hProcess Handle, dwMinimumWorkingSetSize uintptr, dwMaximumWorkingSetSize uintptr, flags uint32) (err error)
|
||||
//sys ClearCommBreak(handle Handle) (err error)
|
||||
//sys ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error)
|
||||
//sys EscapeCommFunction(handle Handle, dwFunc uint32) (err error)
|
||||
//sys GetCommState(handle Handle, lpDCB *DCB) (err error)
|
||||
//sys GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error)
|
||||
//sys GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
|
||||
//sys PurgeComm(handle Handle, dwFlags uint32) (err error)
|
||||
//sys SetCommBreak(handle Handle) (err error)
|
||||
//sys SetCommMask(handle Handle, dwEvtMask uint32) (err error)
|
||||
//sys SetCommState(handle Handle, lpDCB *DCB) (err error)
|
||||
//sys SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error)
|
||||
//sys SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error)
|
||||
//sys WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error)
|
||||
//sys GetActiveProcessorCount(groupNumber uint16) (ret uint32)
|
||||
//sys GetMaximumProcessorCount(groupNumber uint16) (ret uint32)
|
||||
//sys EnumWindows(enumFunc uintptr, param unsafe.Pointer) (err error) = user32.EnumWindows
|
||||
@@ -405,7 +433,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys VerQueryValue(block unsafe.Pointer, subBlock string, pointerToBufferPointer unsafe.Pointer, bufSize *uint32) (err error) = version.VerQueryValueW
|
||||
|
||||
// Process Status API (PSAPI)
|
||||
//sys EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
|
||||
//sys enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) = psapi.EnumProcesses
|
||||
//sys EnumProcessModules(process Handle, module *Handle, cb uint32, cbNeeded *uint32) (err error) = psapi.EnumProcessModules
|
||||
//sys EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *uint32, filterFlag uint32) (err error) = psapi.EnumProcessModulesEx
|
||||
//sys GetModuleInformation(process Handle, module Handle, modinfo *ModuleInfo, cb uint32) (err error) = psapi.GetModuleInformation
|
||||
@@ -437,6 +465,10 @@ func NewCallbackCDecl(fn interface{}) uintptr {
|
||||
//sys DwmGetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmGetWindowAttribute
|
||||
//sys DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, size uint32) (ret error) = dwmapi.DwmSetWindowAttribute
|
||||
|
||||
// Windows Multimedia API
|
||||
//sys TimeBeginPeriod (period uint32) (err error) [failretval != 0] = winmm.timeBeginPeriod
|
||||
//sys TimeEndPeriod (period uint32) (err error) [failretval != 0] = winmm.timeEndPeriod
|
||||
|
||||
// syscall interface implementation for other packages
|
||||
|
||||
// GetCurrentProcess returns the handle for the current process.
|
||||
@@ -695,20 +727,12 @@ func DurationSinceBoot() time.Duration {
|
||||
}
|
||||
|
||||
func Ftruncate(fd Handle, length int64) (err error) {
|
||||
curoffset, e := Seek(fd, 0, 1)
|
||||
if e != nil {
|
||||
return e
|
||||
type _FILE_END_OF_FILE_INFO struct {
|
||||
EndOfFile int64
|
||||
}
|
||||
defer Seek(fd, curoffset, 0)
|
||||
_, e = Seek(fd, length, 0)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
e = SetEndOfFile(fd)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
var info _FILE_END_OF_FILE_INFO
|
||||
info.EndOfFile = length
|
||||
return SetFileInformationByHandle(fd, FileEndOfFileInfo, (*byte)(unsafe.Pointer(&info)), uint32(unsafe.Sizeof(info)))
|
||||
}
|
||||
|
||||
func Gettimeofday(tv *Timeval) (err error) {
|
||||
@@ -864,6 +888,11 @@ const socket_error = uintptr(^uint32(0))
|
||||
//sys GetACP() (acp uint32) = kernel32.GetACP
|
||||
//sys MultiByteToWideChar(codePage uint32, dwFlags uint32, str *byte, nstr int32, wchar *uint16, nwchar int32) (nwrite int32, err error) = kernel32.MultiByteToWideChar
|
||||
//sys getBestInterfaceEx(sockaddr unsafe.Pointer, pdwBestIfIndex *uint32) (errcode error) = iphlpapi.GetBestInterfaceEx
|
||||
//sys GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) = iphlpapi.GetIfEntry2Ex
|
||||
//sys GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) = iphlpapi.GetUnicastIpAddressEntry
|
||||
//sys NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyIpInterfaceChange
|
||||
//sys NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) = iphlpapi.NotifyUnicastIpAddressChange
|
||||
//sys CancelMibChangeNotify2(notificationHandle Handle) (errcode error) = iphlpapi.CancelMibChangeNotify2
|
||||
|
||||
// For testing: clients can set this flag to force
|
||||
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
||||
@@ -964,7 +993,8 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, int32, error) {
|
||||
if n > 0 {
|
||||
sl += int32(n) + 1
|
||||
}
|
||||
if sa.raw.Path[0] == '@' {
|
||||
if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) {
|
||||
// Check sl > 3 so we don't change unnamed socket behavior.
|
||||
sa.raw.Path[0] = 0
|
||||
// Don't count trailing NUL for abstract address.
|
||||
sl--
|
||||
@@ -1347,13 +1377,26 @@ func SetsockoptLinger(fd Handle, level, opt int, l *Linger) (err error) {
|
||||
func SetsockoptInet4Addr(fd Handle, level, opt int, value [4]byte) (err error) {
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(&value[0])), 4)
|
||||
}
|
||||
|
||||
func SetsockoptIPMreq(fd Handle, level, opt int, mreq *IPMreq) (err error) {
|
||||
return Setsockopt(fd, int32(level), int32(opt), (*byte)(unsafe.Pointer(mreq)), int32(unsafe.Sizeof(*mreq)))
|
||||
}
|
||||
|
||||
func SetsockoptIPv6Mreq(fd Handle, level, opt int, mreq *IPv6Mreq) (err error) {
|
||||
return syscall.EWINDOWS
|
||||
}
|
||||
|
||||
func EnumProcesses(processIds []uint32, bytesReturned *uint32) error {
|
||||
// EnumProcesses syscall expects the size parameter to be in bytes, but the code generated with mksyscall uses
|
||||
// the length of the processIds slice instead. Hence, this wrapper function is added to fix the discrepancy.
|
||||
var p *uint32
|
||||
if len(processIds) > 0 {
|
||||
p = &processIds[0]
|
||||
}
|
||||
size := uint32(len(processIds) * 4)
|
||||
return enumProcesses(p, size, bytesReturned)
|
||||
}
|
||||
|
||||
func Getpid() (pid int) { return int(GetCurrentProcessId()) }
|
||||
|
||||
func FindFirstFile(name *uint16, data *Win32finddata) (handle Handle, err error) {
|
||||
@@ -1613,6 +1656,11 @@ func SetConsoleCursorPosition(console Handle, position Coord) error {
|
||||
return setConsoleCursorPosition(console, *((*uint32)(unsafe.Pointer(&position))))
|
||||
}
|
||||
|
||||
func GetStartupInfo(startupInfo *StartupInfo) error {
|
||||
getStartupInfo(startupInfo)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s NTStatus) Errno() syscall.Errno {
|
||||
return rtlNtStatusToDosErrorNoTeb(s)
|
||||
}
|
||||
@@ -1636,23 +1684,22 @@ func (s NTStatus) Error() string {
|
||||
// do not use NTUnicodeString, and instead UTF16PtrFromString should be used for
|
||||
// the more common *uint16 string type.
|
||||
func NewNTUnicodeString(s string) (*NTUnicodeString, error) {
|
||||
var u NTUnicodeString
|
||||
s16, err := UTF16PtrFromString(s)
|
||||
s16, err := UTF16FromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
RtlInitUnicodeString(&u, s16)
|
||||
return &u, nil
|
||||
n := uint16(len(s16) * 2)
|
||||
return &NTUnicodeString{
|
||||
Length: n - 2, // subtract 2 bytes for the NULL terminator
|
||||
MaximumLength: n,
|
||||
Buffer: &s16[0],
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Slice returns a uint16 slice that aliases the data in the NTUnicodeString.
|
||||
func (s *NTUnicodeString) Slice() []uint16 {
|
||||
var slice []uint16
|
||||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice))
|
||||
hdr.Data = unsafe.Pointer(s.Buffer)
|
||||
hdr.Len = int(s.Length)
|
||||
hdr.Cap = int(s.MaximumLength)
|
||||
return slice
|
||||
slice := unsafe.Slice(s.Buffer, s.MaximumLength)
|
||||
return slice[:s.Length]
|
||||
}
|
||||
|
||||
func (s *NTUnicodeString) String() string {
|
||||
@@ -1675,12 +1722,8 @@ func NewNTString(s string) (*NTString, error) {
|
||||
|
||||
// Slice returns a byte slice that aliases the data in the NTString.
|
||||
func (s *NTString) Slice() []byte {
|
||||
var slice []byte
|
||||
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&slice))
|
||||
hdr.Data = unsafe.Pointer(s.Buffer)
|
||||
hdr.Len = int(s.Length)
|
||||
hdr.Cap = int(s.MaximumLength)
|
||||
return slice
|
||||
slice := unsafe.Slice(s.Buffer, s.MaximumLength)
|
||||
return slice[:s.Length]
|
||||
}
|
||||
|
||||
func (s *NTString) String() string {
|
||||
@@ -1732,10 +1775,7 @@ func LoadResourceData(module, resInfo Handle) (data []byte, err error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
h := (*unsafeheader.Slice)(unsafe.Pointer(&data))
|
||||
h.Data = unsafe.Pointer(ptr)
|
||||
h.Len = int(size)
|
||||
h.Cap = int(size)
|
||||
data = unsafe.Slice((*byte)(unsafe.Pointer(ptr)), size)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1806,3 +1846,87 @@ type PSAPI_WORKING_SET_EX_INFORMATION struct {
|
||||
// A PSAPI_WORKING_SET_EX_BLOCK union that indicates the attributes of the page at VirtualAddress.
|
||||
VirtualAttributes PSAPI_WORKING_SET_EX_BLOCK
|
||||
}
|
||||
|
||||
// CreatePseudoConsole creates a windows pseudo console.
|
||||
func CreatePseudoConsole(size Coord, in Handle, out Handle, flags uint32, pconsole *Handle) error {
|
||||
// We need this wrapper to manually cast Coord to uint32. The autogenerated wrappers only
|
||||
// accept arguments that can be casted to uintptr, and Coord can't.
|
||||
return createPseudoConsole(*((*uint32)(unsafe.Pointer(&size))), in, out, flags, pconsole)
|
||||
}
|
||||
|
||||
// ResizePseudoConsole resizes the internal buffers of the pseudo console to the width and height specified in `size`.
|
||||
func ResizePseudoConsole(pconsole Handle, size Coord) error {
|
||||
// We need this wrapper to manually cast Coord to uint32. The autogenerated wrappers only
|
||||
// accept arguments that can be casted to uintptr, and Coord can't.
|
||||
return resizePseudoConsole(pconsole, *((*uint32)(unsafe.Pointer(&size))))
|
||||
}
|
||||
|
||||
// DCB constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-dcb.
|
||||
const (
|
||||
CBR_110 = 110
|
||||
CBR_300 = 300
|
||||
CBR_600 = 600
|
||||
CBR_1200 = 1200
|
||||
CBR_2400 = 2400
|
||||
CBR_4800 = 4800
|
||||
CBR_9600 = 9600
|
||||
CBR_14400 = 14400
|
||||
CBR_19200 = 19200
|
||||
CBR_38400 = 38400
|
||||
CBR_57600 = 57600
|
||||
CBR_115200 = 115200
|
||||
CBR_128000 = 128000
|
||||
CBR_256000 = 256000
|
||||
|
||||
DTR_CONTROL_DISABLE = 0x00000000
|
||||
DTR_CONTROL_ENABLE = 0x00000010
|
||||
DTR_CONTROL_HANDSHAKE = 0x00000020
|
||||
|
||||
RTS_CONTROL_DISABLE = 0x00000000
|
||||
RTS_CONTROL_ENABLE = 0x00001000
|
||||
RTS_CONTROL_HANDSHAKE = 0x00002000
|
||||
RTS_CONTROL_TOGGLE = 0x00003000
|
||||
|
||||
NOPARITY = 0
|
||||
ODDPARITY = 1
|
||||
EVENPARITY = 2
|
||||
MARKPARITY = 3
|
||||
SPACEPARITY = 4
|
||||
|
||||
ONESTOPBIT = 0
|
||||
ONE5STOPBITS = 1
|
||||
TWOSTOPBITS = 2
|
||||
)
|
||||
|
||||
// EscapeCommFunction constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-escapecommfunction.
|
||||
const (
|
||||
SETXOFF = 1
|
||||
SETXON = 2
|
||||
SETRTS = 3
|
||||
CLRRTS = 4
|
||||
SETDTR = 5
|
||||
CLRDTR = 6
|
||||
SETBREAK = 8
|
||||
CLRBREAK = 9
|
||||
)
|
||||
|
||||
// PurgeComm constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-purgecomm.
|
||||
const (
|
||||
PURGE_TXABORT = 0x0001
|
||||
PURGE_RXABORT = 0x0002
|
||||
PURGE_TXCLEAR = 0x0004
|
||||
PURGE_RXCLEAR = 0x0008
|
||||
)
|
||||
|
||||
// SetCommMask constants. See https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setcommmask.
|
||||
const (
|
||||
EV_RXCHAR = 0x0001
|
||||
EV_RXFLAG = 0x0002
|
||||
EV_TXEMPTY = 0x0004
|
||||
EV_CTS = 0x0008
|
||||
EV_DSR = 0x0010
|
||||
EV_RLSD = 0x0020
|
||||
EV_BREAK = 0x0040
|
||||
EV_ERR = 0x0080
|
||||
EV_RING = 0x0100
|
||||
)
|
||||
|
||||
268
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
268
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
@@ -176,6 +176,7 @@ const (
|
||||
WAIT_FAILED = 0xFFFFFFFF
|
||||
|
||||
// Access rights for process.
|
||||
PROCESS_ALL_ACCESS = 0xFFFF
|
||||
PROCESS_CREATE_PROCESS = 0x0080
|
||||
PROCESS_CREATE_THREAD = 0x0002
|
||||
PROCESS_DUP_HANDLE = 0x0040
|
||||
@@ -247,6 +248,7 @@ const (
|
||||
PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY = 0x00020007
|
||||
PROC_THREAD_ATTRIBUTE_UMS_THREAD = 0x00030006
|
||||
PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL = 0x0002000b
|
||||
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE = 0x00020016
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -1059,6 +1061,7 @@ const (
|
||||
SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_INOUT | IOC_WS2 | 6
|
||||
SIO_KEEPALIVE_VALS = IOC_IN | IOC_VENDOR | 4
|
||||
SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12
|
||||
SIO_UDP_NETRESET = IOC_IN | IOC_VENDOR | 15
|
||||
|
||||
// cf. http://support.microsoft.com/default.aspx?scid=kb;en-us;257460
|
||||
|
||||
@@ -1093,7 +1096,33 @@ const (
|
||||
|
||||
SOMAXCONN = 0x7fffffff
|
||||
|
||||
TCP_NODELAY = 1
|
||||
TCP_NODELAY = 1
|
||||
TCP_EXPEDITED_1122 = 2
|
||||
TCP_KEEPALIVE = 3
|
||||
TCP_MAXSEG = 4
|
||||
TCP_MAXRT = 5
|
||||
TCP_STDURG = 6
|
||||
TCP_NOURG = 7
|
||||
TCP_ATMARK = 8
|
||||
TCP_NOSYNRETRIES = 9
|
||||
TCP_TIMESTAMPS = 10
|
||||
TCP_OFFLOAD_PREFERENCE = 11
|
||||
TCP_CONGESTION_ALGORITHM = 12
|
||||
TCP_DELAY_FIN_ACK = 13
|
||||
TCP_MAXRTMS = 14
|
||||
TCP_FASTOPEN = 15
|
||||
TCP_KEEPCNT = 16
|
||||
TCP_KEEPIDLE = TCP_KEEPALIVE
|
||||
TCP_KEEPINTVL = 17
|
||||
TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18
|
||||
TCP_ICMP_ERROR_INFO = 19
|
||||
|
||||
UDP_NOCHECKSUM = 1
|
||||
UDP_SEND_MSG_SIZE = 2
|
||||
UDP_RECV_MAX_COALESCED_SIZE = 3
|
||||
UDP_CHECKSUM_COVERAGE = 20
|
||||
|
||||
UDP_COALESCED_INFO = 3
|
||||
|
||||
SHUT_RD = 0
|
||||
SHUT_WR = 1
|
||||
@@ -1976,7 +2005,21 @@ const (
|
||||
MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
|
||||
)
|
||||
|
||||
const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
|
||||
// Flags for GetAdaptersAddresses, see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses.
|
||||
const (
|
||||
GAA_FLAG_SKIP_UNICAST = 0x1
|
||||
GAA_FLAG_SKIP_ANYCAST = 0x2
|
||||
GAA_FLAG_SKIP_MULTICAST = 0x4
|
||||
GAA_FLAG_SKIP_DNS_SERVER = 0x8
|
||||
GAA_FLAG_INCLUDE_PREFIX = 0x10
|
||||
GAA_FLAG_SKIP_FRIENDLY_NAME = 0x20
|
||||
GAA_FLAG_INCLUDE_WINS_INFO = 0x40
|
||||
GAA_FLAG_INCLUDE_GATEWAYS = 0x80
|
||||
GAA_FLAG_INCLUDE_ALL_INTERFACES = 0x100
|
||||
GAA_FLAG_INCLUDE_ALL_COMPARTMENTS = 0x200
|
||||
GAA_FLAG_INCLUDE_TUNNEL_BINDINGORDER = 0x400
|
||||
)
|
||||
|
||||
const (
|
||||
IF_TYPE_OTHER = 1
|
||||
@@ -1990,6 +2033,50 @@ const (
|
||||
IF_TYPE_IEEE1394 = 144
|
||||
)
|
||||
|
||||
// Enum NL_PREFIX_ORIGIN for [IpAdapterUnicastAddress], see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_prefix_origin
|
||||
const (
|
||||
IpPrefixOriginOther = 0
|
||||
IpPrefixOriginManual = 1
|
||||
IpPrefixOriginWellKnown = 2
|
||||
IpPrefixOriginDhcp = 3
|
||||
IpPrefixOriginRouterAdvertisement = 4
|
||||
IpPrefixOriginUnchanged = 1 << 4
|
||||
)
|
||||
|
||||
// Enum NL_SUFFIX_ORIGIN for [IpAdapterUnicastAddress], see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_suffix_origin
|
||||
const (
|
||||
NlsoOther = 0
|
||||
NlsoManual = 1
|
||||
NlsoWellKnown = 2
|
||||
NlsoDhcp = 3
|
||||
NlsoLinkLayerAddress = 4
|
||||
NlsoRandom = 5
|
||||
IpSuffixOriginOther = 0
|
||||
IpSuffixOriginManual = 1
|
||||
IpSuffixOriginWellKnown = 2
|
||||
IpSuffixOriginDhcp = 3
|
||||
IpSuffixOriginLinkLayerAddress = 4
|
||||
IpSuffixOriginRandom = 5
|
||||
IpSuffixOriginUnchanged = 1 << 4
|
||||
)
|
||||
|
||||
// Enum NL_DAD_STATE for [IpAdapterUnicastAddress], see
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/nldef/ne-nldef-nl_dad_state
|
||||
const (
|
||||
NldsInvalid = 0
|
||||
NldsTentative = 1
|
||||
NldsDuplicate = 2
|
||||
NldsDeprecated = 3
|
||||
NldsPreferred = 4
|
||||
IpDadStateInvalid = 0
|
||||
IpDadStateTentative = 1
|
||||
IpDadStateDuplicate = 2
|
||||
IpDadStateDeprecated = 3
|
||||
IpDadStatePreferred = 4
|
||||
)
|
||||
|
||||
type SocketAddress struct {
|
||||
Sockaddr *syscall.RawSockaddrAny
|
||||
SockaddrLength int32
|
||||
@@ -2117,6 +2204,132 @@ const (
|
||||
IfOperStatusLowerLayerDown = 7
|
||||
)
|
||||
|
||||
const (
|
||||
IF_MAX_PHYS_ADDRESS_LENGTH = 32
|
||||
IF_MAX_STRING_SIZE = 256
|
||||
)
|
||||
|
||||
// MIB_IF_ENTRY_LEVEL enumeration from netioapi.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-getifentry2ex.
|
||||
const (
|
||||
MibIfEntryNormal = 0
|
||||
MibIfEntryNormalWithoutStatistics = 2
|
||||
)
|
||||
|
||||
// MIB_NOTIFICATION_TYPE enumeration from netioapi.h or
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ne-netioapi-mib_notification_type.
|
||||
const (
|
||||
MibParameterNotification = 0
|
||||
MibAddInstance = 1
|
||||
MibDeleteInstance = 2
|
||||
MibInitialNotification = 3
|
||||
)
|
||||
|
||||
// MibIfRow2 stores information about a particular interface. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_if_row2.
|
||||
type MibIfRow2 struct {
|
||||
InterfaceLuid uint64
|
||||
InterfaceIndex uint32
|
||||
InterfaceGuid GUID
|
||||
Alias [IF_MAX_STRING_SIZE + 1]uint16
|
||||
Description [IF_MAX_STRING_SIZE + 1]uint16
|
||||
PhysicalAddressLength uint32
|
||||
PhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
|
||||
PermanentPhysicalAddress [IF_MAX_PHYS_ADDRESS_LENGTH]uint8
|
||||
Mtu uint32
|
||||
Type uint32
|
||||
TunnelType uint32
|
||||
MediaType uint32
|
||||
PhysicalMediumType uint32
|
||||
AccessType uint32
|
||||
DirectionType uint32
|
||||
InterfaceAndOperStatusFlags uint8
|
||||
OperStatus uint32
|
||||
AdminStatus uint32
|
||||
MediaConnectState uint32
|
||||
NetworkGuid GUID
|
||||
ConnectionType uint32
|
||||
TransmitLinkSpeed uint64
|
||||
ReceiveLinkSpeed uint64
|
||||
InOctets uint64
|
||||
InUcastPkts uint64
|
||||
InNUcastPkts uint64
|
||||
InDiscards uint64
|
||||
InErrors uint64
|
||||
InUnknownProtos uint64
|
||||
InUcastOctets uint64
|
||||
InMulticastOctets uint64
|
||||
InBroadcastOctets uint64
|
||||
OutOctets uint64
|
||||
OutUcastPkts uint64
|
||||
OutNUcastPkts uint64
|
||||
OutDiscards uint64
|
||||
OutErrors uint64
|
||||
OutUcastOctets uint64
|
||||
OutMulticastOctets uint64
|
||||
OutBroadcastOctets uint64
|
||||
OutQLen uint64
|
||||
}
|
||||
|
||||
// MIB_UNICASTIPADDRESS_ROW stores information about a unicast IP address. See
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_unicastipaddress_row.
|
||||
type MibUnicastIpAddressRow struct {
|
||||
Address RawSockaddrInet6 // SOCKADDR_INET union
|
||||
InterfaceLuid uint64
|
||||
InterfaceIndex uint32
|
||||
PrefixOrigin uint32
|
||||
SuffixOrigin uint32
|
||||
ValidLifetime uint32
|
||||
PreferredLifetime uint32
|
||||
OnLinkPrefixLength uint8
|
||||
SkipAsSource uint8
|
||||
DadState uint32
|
||||
ScopeId uint32
|
||||
CreationTimeStamp Filetime
|
||||
}
|
||||
|
||||
const ScopeLevelCount = 16
|
||||
|
||||
// MIB_IPINTERFACE_ROW stores interface management information for a particular IP address family on a network interface.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/netioapi/ns-netioapi-mib_ipinterface_row.
|
||||
type MibIpInterfaceRow struct {
|
||||
Family uint16
|
||||
InterfaceLuid uint64
|
||||
InterfaceIndex uint32
|
||||
MaxReassemblySize uint32
|
||||
InterfaceIdentifier uint64
|
||||
MinRouterAdvertisementInterval uint32
|
||||
MaxRouterAdvertisementInterval uint32
|
||||
AdvertisingEnabled uint8
|
||||
ForwardingEnabled uint8
|
||||
WeakHostSend uint8
|
||||
WeakHostReceive uint8
|
||||
UseAutomaticMetric uint8
|
||||
UseNeighborUnreachabilityDetection uint8
|
||||
ManagedAddressConfigurationSupported uint8
|
||||
OtherStatefulConfigurationSupported uint8
|
||||
AdvertiseDefaultRoute uint8
|
||||
RouterDiscoveryBehavior uint32
|
||||
DadTransmits uint32
|
||||
BaseReachableTime uint32
|
||||
RetransmitTime uint32
|
||||
PathMtuDiscoveryTimeout uint32
|
||||
LinkLocalAddressBehavior uint32
|
||||
LinkLocalAddressTimeout uint32
|
||||
ZoneIndices [ScopeLevelCount]uint32
|
||||
SitePrefixLength uint32
|
||||
Metric uint32
|
||||
NlMtu uint32
|
||||
Connected uint8
|
||||
SupportsWakeUpPatterns uint8
|
||||
SupportsNeighborDiscovery uint8
|
||||
SupportsRouterDiscovery uint8
|
||||
ReachableTime uint32
|
||||
TransmitOffload uint32
|
||||
ReceiveOffload uint32
|
||||
DisableDefaultRoutes uint8
|
||||
}
|
||||
|
||||
// Console related constants used for the mode parameter to SetConsoleMode. See
|
||||
// https://docs.microsoft.com/en-us/windows/console/setconsolemode for details.
|
||||
|
||||
@@ -2139,6 +2352,12 @@ const (
|
||||
ENABLE_LVB_GRID_WORLDWIDE = 0x10
|
||||
)
|
||||
|
||||
// Pseudo console related constants used for the flags parameter to
|
||||
// CreatePseudoConsole. See: https://learn.microsoft.com/en-us/windows/console/createpseudoconsole
|
||||
const (
|
||||
PSEUDOCONSOLE_INHERIT_CURSOR = 0x1
|
||||
)
|
||||
|
||||
type Coord struct {
|
||||
X int16
|
||||
Y int16
|
||||
@@ -2220,19 +2439,23 @@ type JOBOBJECT_BASIC_UI_RESTRICTIONS struct {
|
||||
}
|
||||
|
||||
const (
|
||||
// JobObjectInformationClass
|
||||
// JobObjectInformationClass for QueryInformationJobObject and SetInformationJobObject
|
||||
JobObjectAssociateCompletionPortInformation = 7
|
||||
JobObjectBasicAccountingInformation = 1
|
||||
JobObjectBasicAndIoAccountingInformation = 8
|
||||
JobObjectBasicLimitInformation = 2
|
||||
JobObjectBasicProcessIdList = 3
|
||||
JobObjectBasicUIRestrictions = 4
|
||||
JobObjectCpuRateControlInformation = 15
|
||||
JobObjectEndOfJobTimeInformation = 6
|
||||
JobObjectExtendedLimitInformation = 9
|
||||
JobObjectGroupInformation = 11
|
||||
JobObjectGroupInformationEx = 14
|
||||
JobObjectLimitViolationInformation2 = 35
|
||||
JobObjectLimitViolationInformation = 13
|
||||
JobObjectLimitViolationInformation2 = 34
|
||||
JobObjectNetRateControlInformation = 32
|
||||
JobObjectNotificationLimitInformation = 12
|
||||
JobObjectNotificationLimitInformation2 = 34
|
||||
JobObjectNotificationLimitInformation2 = 33
|
||||
JobObjectSecurityLimitInformation = 5
|
||||
)
|
||||
|
||||
@@ -3343,3 +3566,38 @@ type BLOB struct {
|
||||
Size uint32
|
||||
BlobData *byte
|
||||
}
|
||||
|
||||
type ComStat struct {
|
||||
Flags uint32
|
||||
CBInQue uint32
|
||||
CBOutQue uint32
|
||||
}
|
||||
|
||||
type DCB struct {
|
||||
DCBlength uint32
|
||||
BaudRate uint32
|
||||
Flags uint32
|
||||
wReserved uint16
|
||||
XonLim uint16
|
||||
XoffLim uint16
|
||||
ByteSize uint8
|
||||
Parity uint8
|
||||
StopBits uint8
|
||||
XonChar byte
|
||||
XoffChar byte
|
||||
ErrorChar byte
|
||||
EofChar byte
|
||||
EvtChar byte
|
||||
wReserved1 uint16
|
||||
}
|
||||
|
||||
// Keyboard Layout Flags.
|
||||
// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-loadkeyboardlayoutw
|
||||
const (
|
||||
KLF_ACTIVATE = 0x00000001
|
||||
KLF_SUBSTITUTE_OK = 0x00000002
|
||||
KLF_REORDER = 0x00000008
|
||||
KLF_REPLACELANG = 0x00000010
|
||||
KLF_NOTELLSHELL = 0x00000080
|
||||
KLF_SETFORPROCESS = 0x00000100
|
||||
)
|
||||
|
||||
376
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
376
vendor/golang.org/x/sys/windows/zsyscall_windows.go
generated
vendored
@@ -55,6 +55,7 @@ var (
|
||||
moduser32 = NewLazySystemDLL("user32.dll")
|
||||
moduserenv = NewLazySystemDLL("userenv.dll")
|
||||
modversion = NewLazySystemDLL("version.dll")
|
||||
modwinmm = NewLazySystemDLL("winmm.dll")
|
||||
modwintrust = NewLazySystemDLL("wintrust.dll")
|
||||
modws2_32 = NewLazySystemDLL("ws2_32.dll")
|
||||
modwtsapi32 = NewLazySystemDLL("wtsapi32.dll")
|
||||
@@ -86,9 +87,11 @@ var (
|
||||
procDeleteService = modadvapi32.NewProc("DeleteService")
|
||||
procDeregisterEventSource = modadvapi32.NewProc("DeregisterEventSource")
|
||||
procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx")
|
||||
procEnumDependentServicesW = modadvapi32.NewProc("EnumDependentServicesW")
|
||||
procEnumServicesStatusExW = modadvapi32.NewProc("EnumServicesStatusExW")
|
||||
procEqualSid = modadvapi32.NewProc("EqualSid")
|
||||
procFreeSid = modadvapi32.NewProc("FreeSid")
|
||||
procGetAce = modadvapi32.NewProc("GetAce")
|
||||
procGetLengthSid = modadvapi32.NewProc("GetLengthSid")
|
||||
procGetNamedSecurityInfoW = modadvapi32.NewProc("GetNamedSecurityInfoW")
|
||||
procGetSecurityDescriptorControl = modadvapi32.NewProc("GetSecurityDescriptorControl")
|
||||
@@ -178,14 +181,23 @@ var (
|
||||
procDnsRecordListFree = moddnsapi.NewProc("DnsRecordListFree")
|
||||
procDwmGetWindowAttribute = moddwmapi.NewProc("DwmGetWindowAttribute")
|
||||
procDwmSetWindowAttribute = moddwmapi.NewProc("DwmSetWindowAttribute")
|
||||
procCancelMibChangeNotify2 = modiphlpapi.NewProc("CancelMibChangeNotify2")
|
||||
procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
|
||||
procGetAdaptersInfo = modiphlpapi.NewProc("GetAdaptersInfo")
|
||||
procGetBestInterfaceEx = modiphlpapi.NewProc("GetBestInterfaceEx")
|
||||
procGetIfEntry = modiphlpapi.NewProc("GetIfEntry")
|
||||
procGetIfEntry2Ex = modiphlpapi.NewProc("GetIfEntry2Ex")
|
||||
procGetUnicastIpAddressEntry = modiphlpapi.NewProc("GetUnicastIpAddressEntry")
|
||||
procNotifyIpInterfaceChange = modiphlpapi.NewProc("NotifyIpInterfaceChange")
|
||||
procNotifyUnicastIpAddressChange = modiphlpapi.NewProc("NotifyUnicastIpAddressChange")
|
||||
procAddDllDirectory = modkernel32.NewProc("AddDllDirectory")
|
||||
procAssignProcessToJobObject = modkernel32.NewProc("AssignProcessToJobObject")
|
||||
procCancelIo = modkernel32.NewProc("CancelIo")
|
||||
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
|
||||
procClearCommBreak = modkernel32.NewProc("ClearCommBreak")
|
||||
procClearCommError = modkernel32.NewProc("ClearCommError")
|
||||
procCloseHandle = modkernel32.NewProc("CloseHandle")
|
||||
procClosePseudoConsole = modkernel32.NewProc("ClosePseudoConsole")
|
||||
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
|
||||
procCreateDirectoryW = modkernel32.NewProc("CreateDirectoryW")
|
||||
procCreateEventExW = modkernel32.NewProc("CreateEventExW")
|
||||
@@ -200,6 +212,7 @@ var (
|
||||
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
|
||||
procCreatePipe = modkernel32.NewProc("CreatePipe")
|
||||
procCreateProcessW = modkernel32.NewProc("CreateProcessW")
|
||||
procCreatePseudoConsole = modkernel32.NewProc("CreatePseudoConsole")
|
||||
procCreateSymbolicLinkW = modkernel32.NewProc("CreateSymbolicLinkW")
|
||||
procCreateToolhelp32Snapshot = modkernel32.NewProc("CreateToolhelp32Snapshot")
|
||||
procDefineDosDeviceW = modkernel32.NewProc("DefineDosDeviceW")
|
||||
@@ -207,7 +220,9 @@ var (
|
||||
procDeleteProcThreadAttributeList = modkernel32.NewProc("DeleteProcThreadAttributeList")
|
||||
procDeleteVolumeMountPointW = modkernel32.NewProc("DeleteVolumeMountPointW")
|
||||
procDeviceIoControl = modkernel32.NewProc("DeviceIoControl")
|
||||
procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe")
|
||||
procDuplicateHandle = modkernel32.NewProc("DuplicateHandle")
|
||||
procEscapeCommFunction = modkernel32.NewProc("EscapeCommFunction")
|
||||
procExitProcess = modkernel32.NewProc("ExitProcess")
|
||||
procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
|
||||
procFindClose = modkernel32.NewProc("FindClose")
|
||||
@@ -231,11 +246,15 @@ var (
|
||||
procGenerateConsoleCtrlEvent = modkernel32.NewProc("GenerateConsoleCtrlEvent")
|
||||
procGetACP = modkernel32.NewProc("GetACP")
|
||||
procGetActiveProcessorCount = modkernel32.NewProc("GetActiveProcessorCount")
|
||||
procGetCommModemStatus = modkernel32.NewProc("GetCommModemStatus")
|
||||
procGetCommState = modkernel32.NewProc("GetCommState")
|
||||
procGetCommTimeouts = modkernel32.NewProc("GetCommTimeouts")
|
||||
procGetCommandLineW = modkernel32.NewProc("GetCommandLineW")
|
||||
procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW")
|
||||
procGetComputerNameW = modkernel32.NewProc("GetComputerNameW")
|
||||
procGetConsoleCP = modkernel32.NewProc("GetConsoleCP")
|
||||
procGetConsoleMode = modkernel32.NewProc("GetConsoleMode")
|
||||
procGetConsoleOutputCP = modkernel32.NewProc("GetConsoleOutputCP")
|
||||
procGetConsoleScreenBufferInfo = modkernel32.NewProc("GetConsoleScreenBufferInfo")
|
||||
procGetCurrentDirectoryW = modkernel32.NewProc("GetCurrentDirectoryW")
|
||||
procGetCurrentProcessId = modkernel32.NewProc("GetCurrentProcessId")
|
||||
@@ -249,6 +268,7 @@ var (
|
||||
procGetFileAttributesW = modkernel32.NewProc("GetFileAttributesW")
|
||||
procGetFileInformationByHandle = modkernel32.NewProc("GetFileInformationByHandle")
|
||||
procGetFileInformationByHandleEx = modkernel32.NewProc("GetFileInformationByHandleEx")
|
||||
procGetFileTime = modkernel32.NewProc("GetFileTime")
|
||||
procGetFileType = modkernel32.NewProc("GetFileType")
|
||||
procGetFinalPathNameByHandleW = modkernel32.NewProc("GetFinalPathNameByHandleW")
|
||||
procGetFullPathNameW = modkernel32.NewProc("GetFullPathNameW")
|
||||
@@ -260,8 +280,10 @@ var (
|
||||
procGetMaximumProcessorCount = modkernel32.NewProc("GetMaximumProcessorCount")
|
||||
procGetModuleFileNameW = modkernel32.NewProc("GetModuleFileNameW")
|
||||
procGetModuleHandleExW = modkernel32.NewProc("GetModuleHandleExW")
|
||||
procGetNamedPipeClientProcessId = modkernel32.NewProc("GetNamedPipeClientProcessId")
|
||||
procGetNamedPipeHandleStateW = modkernel32.NewProc("GetNamedPipeHandleStateW")
|
||||
procGetNamedPipeInfo = modkernel32.NewProc("GetNamedPipeInfo")
|
||||
procGetNamedPipeServerProcessId = modkernel32.NewProc("GetNamedPipeServerProcessId")
|
||||
procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult")
|
||||
procGetPriorityClass = modkernel32.NewProc("GetPriorityClass")
|
||||
procGetProcAddress = modkernel32.NewProc("GetProcAddress")
|
||||
@@ -316,6 +338,7 @@ var (
|
||||
procProcess32NextW = modkernel32.NewProc("Process32NextW")
|
||||
procProcessIdToSessionId = modkernel32.NewProc("ProcessIdToSessionId")
|
||||
procPulseEvent = modkernel32.NewProc("PulseEvent")
|
||||
procPurgeComm = modkernel32.NewProc("PurgeComm")
|
||||
procQueryDosDeviceW = modkernel32.NewProc("QueryDosDeviceW")
|
||||
procQueryFullProcessImageNameW = modkernel32.NewProc("QueryFullProcessImageNameW")
|
||||
procQueryInformationJobObject = modkernel32.NewProc("QueryInformationJobObject")
|
||||
@@ -325,11 +348,18 @@ var (
|
||||
procReadProcessMemory = modkernel32.NewProc("ReadProcessMemory")
|
||||
procReleaseMutex = modkernel32.NewProc("ReleaseMutex")
|
||||
procRemoveDirectoryW = modkernel32.NewProc("RemoveDirectoryW")
|
||||
procRemoveDllDirectory = modkernel32.NewProc("RemoveDllDirectory")
|
||||
procResetEvent = modkernel32.NewProc("ResetEvent")
|
||||
procResizePseudoConsole = modkernel32.NewProc("ResizePseudoConsole")
|
||||
procResumeThread = modkernel32.NewProc("ResumeThread")
|
||||
procSetCommBreak = modkernel32.NewProc("SetCommBreak")
|
||||
procSetCommMask = modkernel32.NewProc("SetCommMask")
|
||||
procSetCommState = modkernel32.NewProc("SetCommState")
|
||||
procSetCommTimeouts = modkernel32.NewProc("SetCommTimeouts")
|
||||
procSetConsoleCP = modkernel32.NewProc("SetConsoleCP")
|
||||
procSetConsoleCursorPosition = modkernel32.NewProc("SetConsoleCursorPosition")
|
||||
procSetConsoleMode = modkernel32.NewProc("SetConsoleMode")
|
||||
procSetConsoleOutputCP = modkernel32.NewProc("SetConsoleOutputCP")
|
||||
procSetCurrentDirectoryW = modkernel32.NewProc("SetCurrentDirectoryW")
|
||||
procSetDefaultDllDirectories = modkernel32.NewProc("SetDefaultDllDirectories")
|
||||
procSetDllDirectoryW = modkernel32.NewProc("SetDllDirectoryW")
|
||||
@@ -342,6 +372,7 @@ var (
|
||||
procSetFileInformationByHandle = modkernel32.NewProc("SetFileInformationByHandle")
|
||||
procSetFilePointer = modkernel32.NewProc("SetFilePointer")
|
||||
procSetFileTime = modkernel32.NewProc("SetFileTime")
|
||||
procSetFileValidData = modkernel32.NewProc("SetFileValidData")
|
||||
procSetHandleInformation = modkernel32.NewProc("SetHandleInformation")
|
||||
procSetInformationJobObject = modkernel32.NewProc("SetInformationJobObject")
|
||||
procSetNamedPipeHandleState = modkernel32.NewProc("SetNamedPipeHandleState")
|
||||
@@ -352,6 +383,7 @@ var (
|
||||
procSetStdHandle = modkernel32.NewProc("SetStdHandle")
|
||||
procSetVolumeLabelW = modkernel32.NewProc("SetVolumeLabelW")
|
||||
procSetVolumeMountPointW = modkernel32.NewProc("SetVolumeMountPointW")
|
||||
procSetupComm = modkernel32.NewProc("SetupComm")
|
||||
procSizeofResource = modkernel32.NewProc("SizeofResource")
|
||||
procSleepEx = modkernel32.NewProc("SleepEx")
|
||||
procTerminateJobObject = modkernel32.NewProc("TerminateJobObject")
|
||||
@@ -370,6 +402,7 @@ var (
|
||||
procVirtualQueryEx = modkernel32.NewProc("VirtualQueryEx")
|
||||
procVirtualUnlock = modkernel32.NewProc("VirtualUnlock")
|
||||
procWTSGetActiveConsoleSessionId = modkernel32.NewProc("WTSGetActiveConsoleSessionId")
|
||||
procWaitCommEvent = modkernel32.NewProc("WaitCommEvent")
|
||||
procWaitForMultipleObjects = modkernel32.NewProc("WaitForMultipleObjects")
|
||||
procWaitForSingleObject = modkernel32.NewProc("WaitForSingleObject")
|
||||
procWriteConsoleW = modkernel32.NewProc("WriteConsoleW")
|
||||
@@ -380,6 +413,7 @@ var (
|
||||
procTransmitFile = modmswsock.NewProc("TransmitFile")
|
||||
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
|
||||
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
|
||||
procNetUserEnum = modnetapi32.NewProc("NetUserEnum")
|
||||
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
|
||||
procNtCreateFile = modntdll.NewProc("NtCreateFile")
|
||||
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
|
||||
@@ -455,18 +489,24 @@ var (
|
||||
procGetDesktopWindow = moduser32.NewProc("GetDesktopWindow")
|
||||
procGetForegroundWindow = moduser32.NewProc("GetForegroundWindow")
|
||||
procGetGUIThreadInfo = moduser32.NewProc("GetGUIThreadInfo")
|
||||
procGetKeyboardLayout = moduser32.NewProc("GetKeyboardLayout")
|
||||
procGetShellWindow = moduser32.NewProc("GetShellWindow")
|
||||
procGetWindowThreadProcessId = moduser32.NewProc("GetWindowThreadProcessId")
|
||||
procIsWindow = moduser32.NewProc("IsWindow")
|
||||
procIsWindowUnicode = moduser32.NewProc("IsWindowUnicode")
|
||||
procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
|
||||
procLoadKeyboardLayoutW = moduser32.NewProc("LoadKeyboardLayoutW")
|
||||
procMessageBoxW = moduser32.NewProc("MessageBoxW")
|
||||
procToUnicodeEx = moduser32.NewProc("ToUnicodeEx")
|
||||
procUnloadKeyboardLayout = moduser32.NewProc("UnloadKeyboardLayout")
|
||||
procCreateEnvironmentBlock = moduserenv.NewProc("CreateEnvironmentBlock")
|
||||
procDestroyEnvironmentBlock = moduserenv.NewProc("DestroyEnvironmentBlock")
|
||||
procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW")
|
||||
procGetFileVersionInfoSizeW = modversion.NewProc("GetFileVersionInfoSizeW")
|
||||
procGetFileVersionInfoW = modversion.NewProc("GetFileVersionInfoW")
|
||||
procVerQueryValueW = modversion.NewProc("VerQueryValueW")
|
||||
proctimeBeginPeriod = modwinmm.NewProc("timeBeginPeriod")
|
||||
proctimeEndPeriod = modwinmm.NewProc("timeEndPeriod")
|
||||
procWinVerifyTrustEx = modwintrust.NewProc("WinVerifyTrustEx")
|
||||
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
|
||||
procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
|
||||
@@ -734,6 +774,14 @@ func DuplicateTokenEx(existingToken Token, desiredAccess uint32, tokenAttributes
|
||||
return
|
||||
}
|
||||
|
||||
func EnumDependentServices(service Handle, activityState uint32, services *ENUM_SERVICE_STATUS, buffSize uint32, bytesNeeded *uint32, servicesReturned *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procEnumDependentServicesW.Addr(), 6, uintptr(service), uintptr(activityState), uintptr(unsafe.Pointer(services)), uintptr(buffSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func EnumServicesStatusEx(mgr Handle, infoLevel uint32, serviceType uint32, serviceState uint32, services *byte, bufSize uint32, bytesNeeded *uint32, servicesReturned *uint32, resumeHandle *uint32, groupName *uint16) (err error) {
|
||||
r1, _, e1 := syscall.Syscall12(procEnumServicesStatusExW.Addr(), 10, uintptr(mgr), uintptr(infoLevel), uintptr(serviceType), uintptr(serviceState), uintptr(unsafe.Pointer(services)), uintptr(bufSize), uintptr(unsafe.Pointer(bytesNeeded)), uintptr(unsafe.Pointer(servicesReturned)), uintptr(unsafe.Pointer(resumeHandle)), uintptr(unsafe.Pointer(groupName)), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -756,6 +804,14 @@ func FreeSid(sid *SID) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetAce(acl *ACL, aceIndex uint32, pAce **ACCESS_ALLOWED_ACE) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetAce.Addr(), 3, uintptr(unsafe.Pointer(acl)), uintptr(aceIndex), uintptr(unsafe.Pointer(pAce)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetLengthSid(sid *SID) (len uint32) {
|
||||
r0, _, _ := syscall.Syscall(procGetLengthSid.Addr(), 1, uintptr(unsafe.Pointer(sid)), 0, 0)
|
||||
len = uint32(r0)
|
||||
@@ -1557,6 +1613,14 @@ func DwmSetWindowAttribute(hwnd HWND, attribute uint32, value unsafe.Pointer, si
|
||||
return
|
||||
}
|
||||
|
||||
func CancelMibChangeNotify2(notificationHandle Handle) (errcode error) {
|
||||
r0, _, _ := syscall.Syscall(procCancelMibChangeNotify2.Addr(), 1, uintptr(notificationHandle), 0, 0)
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizePointer *uint32) (errcode error) {
|
||||
r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizePointer)), 0)
|
||||
if r0 != 0 {
|
||||
@@ -1589,6 +1653,55 @@ func GetIfEntry(pIfRow *MibIfRow) (errcode error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetIfEntry2Ex(level uint32, row *MibIfRow2) (errcode error) {
|
||||
r0, _, _ := syscall.Syscall(procGetIfEntry2Ex.Addr(), 2, uintptr(level), uintptr(unsafe.Pointer(row)), 0)
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetUnicastIpAddressEntry(row *MibUnicastIpAddressRow) (errcode error) {
|
||||
r0, _, _ := syscall.Syscall(procGetUnicastIpAddressEntry.Addr(), 1, uintptr(unsafe.Pointer(row)), 0, 0)
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NotifyIpInterfaceChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, _ := syscall.Syscall6(procNotifyIpInterfaceChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0)
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NotifyUnicastIpAddressChange(family uint16, callback uintptr, callerContext unsafe.Pointer, initialNotification bool, notificationHandle *Handle) (errcode error) {
|
||||
var _p0 uint32
|
||||
if initialNotification {
|
||||
_p0 = 1
|
||||
}
|
||||
r0, _, _ := syscall.Syscall6(procNotifyUnicastIpAddressChange.Addr(), 5, uintptr(family), uintptr(callback), uintptr(callerContext), uintptr(_p0), uintptr(unsafe.Pointer(notificationHandle)), 0)
|
||||
if r0 != 0 {
|
||||
errcode = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AddDllDirectory(path *uint16) (cookie uintptr, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procAddDllDirectory.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
|
||||
cookie = uintptr(r0)
|
||||
if cookie == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func AssignProcessToJobObject(job Handle, process Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procAssignProcessToJobObject.Addr(), 2, uintptr(job), uintptr(process), 0)
|
||||
if r1 == 0 {
|
||||
@@ -1613,6 +1726,22 @@ func CancelIoEx(s Handle, o *Overlapped) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ClearCommBreak(handle Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procClearCommBreak.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ClearCommError(handle Handle, lpErrors *uint32, lpStat *ComStat) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procClearCommError.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpErrors)), uintptr(unsafe.Pointer(lpStat)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CloseHandle(handle Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCloseHandle.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -1621,6 +1750,11 @@ func CloseHandle(handle Handle) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ClosePseudoConsole(console Handle) {
|
||||
syscall.Syscall(procClosePseudoConsole.Addr(), 1, uintptr(console), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
func ConnectNamedPipe(pipe Handle, overlapped *Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(overlapped)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -1750,6 +1884,14 @@ func CreateProcess(appName *uint16, commandLine *uint16, procSecurity *SecurityA
|
||||
return
|
||||
}
|
||||
|
||||
func createPseudoConsole(size uint32, in Handle, out Handle, flags uint32, pconsole *Handle) (hr error) {
|
||||
r0, _, _ := syscall.Syscall6(procCreatePseudoConsole.Addr(), 5, uintptr(size), uintptr(in), uintptr(out), uintptr(flags), uintptr(unsafe.Pointer(pconsole)), 0)
|
||||
if r0 != 0 {
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateSymbolicLink(symlinkfilename *uint16, targetfilename *uint16, flags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procCreateSymbolicLinkW.Addr(), 3, uintptr(unsafe.Pointer(symlinkfilename)), uintptr(unsafe.Pointer(targetfilename)), uintptr(flags))
|
||||
if r1&0xff == 0 {
|
||||
@@ -1804,6 +1946,14 @@ func DeviceIoControl(handle Handle, ioControlCode uint32, inBuffer *byte, inBuff
|
||||
return
|
||||
}
|
||||
|
||||
func DisconnectNamedPipe(pipe Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(pipe), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetProcessHandle Handle, lpTargetHandle *Handle, dwDesiredAccess uint32, bInheritHandle bool, dwOptions uint32) (err error) {
|
||||
var _p0 uint32
|
||||
if bInheritHandle {
|
||||
@@ -1816,6 +1966,14 @@ func DuplicateHandle(hSourceProcessHandle Handle, hSourceHandle Handle, hTargetP
|
||||
return
|
||||
}
|
||||
|
||||
func EscapeCommFunction(handle Handle, dwFunc uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procEscapeCommFunction.Addr(), 2, uintptr(handle), uintptr(dwFunc), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ExitProcess(exitcode uint32) {
|
||||
syscall.Syscall(procExitProcess.Addr(), 1, uintptr(exitcode), 0, 0)
|
||||
return
|
||||
@@ -2017,6 +2175,22 @@ func GetActiveProcessorCount(groupNumber uint16) (ret uint32) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetCommModemStatus(handle Handle, lpModemStat *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetCommModemStatus.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpModemStat)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetCommState(handle Handle, lpDCB *DCB) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -2047,6 +2221,15 @@ func GetComputerName(buf *uint16, n *uint32) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetConsoleCP() (cp uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetConsoleCP.Addr(), 0, 0, 0, 0)
|
||||
cp = uint32(r0)
|
||||
if cp == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetConsoleMode(console Handle, mode *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetConsoleMode.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(mode)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -2055,6 +2238,15 @@ func GetConsoleMode(console Handle, mode *uint32) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetConsoleOutputCP() (cp uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetConsoleOutputCP.Addr(), 0, 0, 0, 0)
|
||||
cp = uint32(r0)
|
||||
if cp == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetConsoleScreenBufferInfo(console Handle, info *ConsoleScreenBufferInfo) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetConsoleScreenBufferInfo.Addr(), 2, uintptr(console), uintptr(unsafe.Pointer(info)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -2157,6 +2349,14 @@ func GetFileInformationByHandleEx(handle Handle, class uint32, outBuffer *byte,
|
||||
return
|
||||
}
|
||||
|
||||
func GetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetime) (err error) {
|
||||
r1, _, e1 := syscall.Syscall6(procGetFileTime.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(ctime)), uintptr(unsafe.Pointer(atime)), uintptr(unsafe.Pointer(wtime)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetFileType(filehandle Handle) (n uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procGetFileType.Addr(), 1, uintptr(filehandle), 0, 0)
|
||||
n = uint32(r0)
|
||||
@@ -2248,6 +2448,14 @@ func GetModuleHandleEx(flags uint32, moduleName *uint16, module *Handle) (err er
|
||||
return
|
||||
}
|
||||
|
||||
func GetNamedPipeClientProcessId(pipe Handle, clientProcessID *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetNamedPipeClientProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(clientProcessID)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetNamedPipeHandleState(pipe Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall9(procGetNamedPipeHandleStateW.Addr(), 7, uintptr(pipe), uintptr(unsafe.Pointer(state)), uintptr(unsafe.Pointer(curInstances)), uintptr(unsafe.Pointer(maxCollectionCount)), uintptr(unsafe.Pointer(collectDataTimeout)), uintptr(unsafe.Pointer(userName)), uintptr(maxUserNameSize), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -2264,6 +2472,14 @@ func GetNamedPipeInfo(pipe Handle, flags *uint32, outSize *uint32, inSize *uint3
|
||||
return
|
||||
}
|
||||
|
||||
func GetNamedPipeServerProcessId(pipe Handle, serverProcessID *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetNamedPipeServerProcessId.Addr(), 2, uintptr(pipe), uintptr(unsafe.Pointer(serverProcessID)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func GetOverlappedResult(handle Handle, overlapped *Overlapped, done *uint32, wait bool) (err error) {
|
||||
var _p0 uint32
|
||||
if wait {
|
||||
@@ -2358,11 +2574,8 @@ func GetShortPathName(longpath *uint16, shortpath *uint16, buflen uint32) (n uin
|
||||
return
|
||||
}
|
||||
|
||||
func GetStartupInfo(startupInfo *StartupInfo) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
func getStartupInfo(startupInfo *StartupInfo) {
|
||||
syscall.Syscall(procGetStartupInfoW.Addr(), 1, uintptr(unsafe.Pointer(startupInfo)), 0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2764,6 +2977,14 @@ func PulseEvent(event Handle) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func PurgeComm(handle Handle, dwFlags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procPurgeComm.Addr(), 2, uintptr(handle), uintptr(dwFlags), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func QueryDosDevice(deviceName *uint16, targetPath *uint16, max uint32) (n uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procQueryDosDeviceW.Addr(), 3, uintptr(unsafe.Pointer(deviceName)), uintptr(unsafe.Pointer(targetPath)), uintptr(max))
|
||||
n = uint32(r0)
|
||||
@@ -2845,6 +3066,14 @@ func RemoveDirectory(path *uint16) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func RemoveDllDirectory(cookie uintptr) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procRemoveDllDirectory.Addr(), 1, uintptr(cookie), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ResetEvent(event Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procResetEvent.Addr(), 1, uintptr(event), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -2853,6 +3082,14 @@ func ResetEvent(event Handle) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func resizePseudoConsole(pconsole Handle, size uint32) (hr error) {
|
||||
r0, _, _ := syscall.Syscall(procResizePseudoConsole.Addr(), 2, uintptr(pconsole), uintptr(size), 0)
|
||||
if r0 != 0 {
|
||||
hr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ResumeThread(thread Handle) (ret uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procResumeThread.Addr(), 1, uintptr(thread), 0, 0)
|
||||
ret = uint32(r0)
|
||||
@@ -2862,6 +3099,30 @@ func ResumeThread(thread Handle) (ret uint32, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetCommBreak(handle Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommBreak.Addr(), 1, uintptr(handle), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetCommMask(handle Handle, dwEvtMask uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommMask.Addr(), 2, uintptr(handle), uintptr(dwEvtMask), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetCommState(handle Handle, lpDCB *DCB) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommState.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(lpDCB)), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCommTimeouts.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(timeouts)), 0)
|
||||
if r1 == 0 {
|
||||
@@ -2870,6 +3131,14 @@ func SetCommTimeouts(handle Handle, timeouts *CommTimeouts) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetConsoleCP(cp uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetConsoleCP.Addr(), 1, uintptr(cp), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func setConsoleCursorPosition(console Handle, position uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetConsoleCursorPosition.Addr(), 2, uintptr(console), uintptr(position), 0)
|
||||
if r1 == 0 {
|
||||
@@ -2886,6 +3155,14 @@ func SetConsoleMode(console Handle, mode uint32) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func SetConsoleOutputCP(cp uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetConsoleOutputCP.Addr(), 1, uintptr(cp), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetCurrentDirectory(path *uint16) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetCurrentDirectoryW.Addr(), 1, uintptr(unsafe.Pointer(path)), 0, 0)
|
||||
if r1 == 0 {
|
||||
@@ -2990,6 +3267,14 @@ func SetFileTime(handle Handle, ctime *Filetime, atime *Filetime, wtime *Filetim
|
||||
return
|
||||
}
|
||||
|
||||
func SetFileValidData(handle Handle, validDataLength int64) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetFileValidData.Addr(), 2, uintptr(handle), uintptr(validDataLength), 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SetHandleInformation(handle Handle, mask uint32, flags uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetHandleInformation.Addr(), 3, uintptr(handle), uintptr(mask), uintptr(flags))
|
||||
if r1 == 0 {
|
||||
@@ -3075,6 +3360,14 @@ func SetVolumeMountPoint(volumeMountPoint *uint16, volumeName *uint16) (err erro
|
||||
return
|
||||
}
|
||||
|
||||
func SetupComm(handle Handle, dwInQueue uint32, dwOutQueue uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procSetupComm.Addr(), 3, uintptr(handle), uintptr(dwInQueue), uintptr(dwOutQueue))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func SizeofResource(module Handle, resInfo Handle) (size uint32, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procSizeofResource.Addr(), 2, uintptr(module), uintptr(resInfo), 0)
|
||||
size = uint32(r0)
|
||||
@@ -3221,6 +3514,14 @@ func WTSGetActiveConsoleSessionId() (sessionID uint32) {
|
||||
return
|
||||
}
|
||||
|
||||
func WaitCommEvent(handle Handle, lpEvtMask *uint32, lpOverlapped *Overlapped) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procWaitCommEvent.Addr(), 3, uintptr(handle), uintptr(unsafe.Pointer(lpEvtMask)), uintptr(unsafe.Pointer(lpOverlapped)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func waitForMultipleObjects(count uint32, handles uintptr, waitAll bool, waitMilliseconds uint32) (event uint32, err error) {
|
||||
var _p0 uint32
|
||||
if waitAll {
|
||||
@@ -3308,6 +3609,14 @@ func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (nete
|
||||
return
|
||||
}
|
||||
|
||||
func NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) {
|
||||
r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), uintptr(unsafe.Pointer(resumeHandle)), 0)
|
||||
if r0 != 0 {
|
||||
neterr = syscall.Errno(r0)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
|
||||
r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
|
||||
if r0 != 0 {
|
||||
@@ -3507,12 +3816,8 @@ func EnumProcessModulesEx(process Handle, module *Handle, cb uint32, cbNeeded *u
|
||||
return
|
||||
}
|
||||
|
||||
func EnumProcesses(processIds []uint32, bytesReturned *uint32) (err error) {
|
||||
var _p0 *uint32
|
||||
if len(processIds) > 0 {
|
||||
_p0 = &processIds[0]
|
||||
}
|
||||
r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(len(processIds)), uintptr(unsafe.Pointer(bytesReturned)))
|
||||
func enumProcesses(processIds *uint32, nSize uint32, bytesReturned *uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procEnumProcesses.Addr(), 3, uintptr(unsafe.Pointer(processIds)), uintptr(nSize), uintptr(unsafe.Pointer(bytesReturned)))
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -3815,9 +4120,9 @@ func setupUninstallOEMInf(infFileName *uint16, flags SUOI, reserved uintptr) (er
|
||||
return
|
||||
}
|
||||
|
||||
func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) {
|
||||
func commandLineToArgv(cmd *uint16, argc *int32) (argv **uint16, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procCommandLineToArgvW.Addr(), 2, uintptr(unsafe.Pointer(cmd)), uintptr(unsafe.Pointer(argc)), 0)
|
||||
argv = (*[8192]*[8192]uint16)(unsafe.Pointer(r0))
|
||||
argv = (**uint16)(unsafe.Pointer(r0))
|
||||
if argv == nil {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
@@ -3890,6 +4195,12 @@ func GetGUIThreadInfo(thread uint32, info *GUIThreadInfo) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func GetKeyboardLayout(tid uint32) (hkl Handle) {
|
||||
r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(tid), 0, 0)
|
||||
hkl = Handle(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func GetShellWindow() (shellWindow HWND) {
|
||||
r0, _, _ := syscall.Syscall(procGetShellWindow.Addr(), 0, 0, 0, 0)
|
||||
shellWindow = HWND(r0)
|
||||
@@ -3923,6 +4234,15 @@ func IsWindowVisible(hwnd HWND) (isVisible bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func LoadKeyboardLayout(name *uint16, flags uint32) (hkl Handle, err error) {
|
||||
r0, _, e1 := syscall.Syscall(procLoadKeyboardLayoutW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(flags), 0)
|
||||
hkl = Handle(r0)
|
||||
if hkl == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret int32, err error) {
|
||||
r0, _, e1 := syscall.Syscall6(procMessageBoxW.Addr(), 4, uintptr(hwnd), uintptr(unsafe.Pointer(text)), uintptr(unsafe.Pointer(caption)), uintptr(boxtype), 0, 0)
|
||||
ret = int32(r0)
|
||||
@@ -3932,6 +4252,20 @@ func MessageBox(hwnd HWND, text *uint16, caption *uint16, boxtype uint32) (ret i
|
||||
return
|
||||
}
|
||||
|
||||
func ToUnicodeEx(vkey uint32, scancode uint32, keystate *byte, pwszBuff *uint16, cchBuff int32, flags uint32, hkl Handle) (ret int32) {
|
||||
r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(vkey), uintptr(scancode), uintptr(unsafe.Pointer(keystate)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(flags), uintptr(hkl), 0, 0)
|
||||
ret = int32(r0)
|
||||
return
|
||||
}
|
||||
|
||||
func UnloadKeyboardLayout(hkl Handle) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(procUnloadKeyboardLayout.Addr(), 1, uintptr(hkl), 0, 0)
|
||||
if r1 == 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func CreateEnvironmentBlock(block **uint16, token Token, inheritExisting bool) (err error) {
|
||||
var _p0 uint32
|
||||
if inheritExisting {
|
||||
@@ -4012,6 +4346,22 @@ func _VerQueryValue(block unsafe.Pointer, subBlock *uint16, pointerToBufferPoint
|
||||
return
|
||||
}
|
||||
|
||||
func TimeBeginPeriod(period uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(proctimeBeginPeriod.Addr(), 1, uintptr(period), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func TimeEndPeriod(period uint32) (err error) {
|
||||
r1, _, e1 := syscall.Syscall(proctimeEndPeriod.Addr(), 1, uintptr(period), 0, 0)
|
||||
if r1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func WinVerifyTrustEx(hwnd HWND, actionId *GUID, data *WinTrustData) (ret error) {
|
||||
r0, _, _ := syscall.Syscall(procWinVerifyTrustEx.Addr(), 3, uintptr(hwnd), uintptr(unsafe.Pointer(actionId)), uintptr(unsafe.Pointer(data)))
|
||||
if r0 != 0 {
|
||||
|
||||
4
vendor/golang.org/x/text/LICENSE
generated
vendored
4
vendor/golang.org/x/text/LICENSE
generated
vendored
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
@@ -10,7 +10,7 @@ notice, this list of conditions and the following disclaimer.
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
|
||||
356
vendor/golang.org/x/text/internal/language/compact/tables.go
generated
vendored
356
vendor/golang.org/x/text/internal/language/compact/tables.go
generated
vendored
@@ -790,226 +790,226 @@ const (
|
||||
|
||||
var coreTags = []language.CompactCoreInfo{ // 773 elements
|
||||
// Entry 0 - 1F
|
||||
0x00000000, 0x01600000, 0x016000d2, 0x01600161,
|
||||
0x01c00000, 0x01c00052, 0x02100000, 0x02100080,
|
||||
0x02700000, 0x0270006f, 0x03a00000, 0x03a00001,
|
||||
0x03a00023, 0x03a00039, 0x03a00062, 0x03a00067,
|
||||
0x03a0006b, 0x03a0006c, 0x03a0006d, 0x03a00097,
|
||||
0x03a0009b, 0x03a000a1, 0x03a000a8, 0x03a000ac,
|
||||
0x03a000b0, 0x03a000b9, 0x03a000ba, 0x03a000c9,
|
||||
0x03a000e1, 0x03a000ed, 0x03a000f3, 0x03a00108,
|
||||
0x00000000, 0x01600000, 0x016000d3, 0x01600162,
|
||||
0x01c00000, 0x01c00052, 0x02100000, 0x02100081,
|
||||
0x02700000, 0x02700070, 0x03a00000, 0x03a00001,
|
||||
0x03a00023, 0x03a00039, 0x03a00063, 0x03a00068,
|
||||
0x03a0006c, 0x03a0006d, 0x03a0006e, 0x03a00098,
|
||||
0x03a0009c, 0x03a000a2, 0x03a000a9, 0x03a000ad,
|
||||
0x03a000b1, 0x03a000ba, 0x03a000bb, 0x03a000ca,
|
||||
0x03a000e2, 0x03a000ee, 0x03a000f4, 0x03a00109,
|
||||
// Entry 20 - 3F
|
||||
0x03a0010b, 0x03a00115, 0x03a00117, 0x03a0011c,
|
||||
0x03a00120, 0x03a00128, 0x03a0015e, 0x04000000,
|
||||
0x04300000, 0x04300099, 0x04400000, 0x0440012f,
|
||||
0x04800000, 0x0480006e, 0x05800000, 0x05820000,
|
||||
0x05820032, 0x0585a000, 0x0585a032, 0x05e00000,
|
||||
0x03a0010c, 0x03a00116, 0x03a00118, 0x03a0011d,
|
||||
0x03a00121, 0x03a00129, 0x03a0015f, 0x04000000,
|
||||
0x04300000, 0x0430009a, 0x04400000, 0x04400130,
|
||||
0x04800000, 0x0480006f, 0x05800000, 0x05820000,
|
||||
0x05820032, 0x0585b000, 0x0585b032, 0x05e00000,
|
||||
0x05e00052, 0x07100000, 0x07100047, 0x07500000,
|
||||
0x07500162, 0x07900000, 0x0790012f, 0x07e00000,
|
||||
0x07e00038, 0x08200000, 0x0a000000, 0x0a0000c3,
|
||||
0x07500163, 0x07900000, 0x07900130, 0x07e00000,
|
||||
0x07e00038, 0x08200000, 0x0a000000, 0x0a0000c4,
|
||||
// Entry 40 - 5F
|
||||
0x0a500000, 0x0a500035, 0x0a500099, 0x0a900000,
|
||||
0x0a900053, 0x0a900099, 0x0b200000, 0x0b200078,
|
||||
0x0b500000, 0x0b500099, 0x0b700000, 0x0b720000,
|
||||
0x0b720033, 0x0b75a000, 0x0b75a033, 0x0d700000,
|
||||
0x0d700022, 0x0d70006e, 0x0d700078, 0x0d70009e,
|
||||
0x0db00000, 0x0db00035, 0x0db00099, 0x0dc00000,
|
||||
0x0dc00106, 0x0df00000, 0x0df00131, 0x0e500000,
|
||||
0x0e500135, 0x0e900000, 0x0e90009b, 0x0e90009c,
|
||||
0x0a500000, 0x0a500035, 0x0a50009a, 0x0a900000,
|
||||
0x0a900053, 0x0a90009a, 0x0b200000, 0x0b200079,
|
||||
0x0b500000, 0x0b50009a, 0x0b700000, 0x0b720000,
|
||||
0x0b720033, 0x0b75b000, 0x0b75b033, 0x0d700000,
|
||||
0x0d700022, 0x0d70006f, 0x0d700079, 0x0d70009f,
|
||||
0x0db00000, 0x0db00035, 0x0db0009a, 0x0dc00000,
|
||||
0x0dc00107, 0x0df00000, 0x0df00132, 0x0e500000,
|
||||
0x0e500136, 0x0e900000, 0x0e90009c, 0x0e90009d,
|
||||
// Entry 60 - 7F
|
||||
0x0fa00000, 0x0fa0005e, 0x0fe00000, 0x0fe00106,
|
||||
0x10000000, 0x1000007b, 0x10100000, 0x10100063,
|
||||
0x10100082, 0x10800000, 0x108000a4, 0x10d00000,
|
||||
0x10d0002e, 0x10d00036, 0x10d0004e, 0x10d00060,
|
||||
0x10d0009e, 0x10d000b2, 0x10d000b7, 0x11700000,
|
||||
0x117000d4, 0x11f00000, 0x11f00060, 0x12400000,
|
||||
0x12400052, 0x12800000, 0x12b00000, 0x12b00114,
|
||||
0x12d00000, 0x12d00043, 0x12f00000, 0x12f000a4,
|
||||
0x0fa00000, 0x0fa0005f, 0x0fe00000, 0x0fe00107,
|
||||
0x10000000, 0x1000007c, 0x10100000, 0x10100064,
|
||||
0x10100083, 0x10800000, 0x108000a5, 0x10d00000,
|
||||
0x10d0002e, 0x10d00036, 0x10d0004e, 0x10d00061,
|
||||
0x10d0009f, 0x10d000b3, 0x10d000b8, 0x11700000,
|
||||
0x117000d5, 0x11f00000, 0x11f00061, 0x12400000,
|
||||
0x12400052, 0x12800000, 0x12b00000, 0x12b00115,
|
||||
0x12d00000, 0x12d00043, 0x12f00000, 0x12f000a5,
|
||||
// Entry 80 - 9F
|
||||
0x13000000, 0x13000080, 0x13000122, 0x13600000,
|
||||
0x1360005d, 0x13600087, 0x13900000, 0x13900001,
|
||||
0x13000000, 0x13000081, 0x13000123, 0x13600000,
|
||||
0x1360005e, 0x13600088, 0x13900000, 0x13900001,
|
||||
0x1390001a, 0x13900025, 0x13900026, 0x1390002d,
|
||||
0x1390002e, 0x1390002f, 0x13900034, 0x13900036,
|
||||
0x1390003a, 0x1390003d, 0x13900042, 0x13900046,
|
||||
0x13900048, 0x13900049, 0x1390004a, 0x1390004e,
|
||||
0x13900050, 0x13900052, 0x1390005c, 0x1390005d,
|
||||
0x13900060, 0x13900061, 0x13900063, 0x13900064,
|
||||
0x13900050, 0x13900052, 0x1390005d, 0x1390005e,
|
||||
0x13900061, 0x13900062, 0x13900064, 0x13900065,
|
||||
// Entry A0 - BF
|
||||
0x1390006d, 0x13900072, 0x13900073, 0x13900074,
|
||||
0x13900075, 0x1390007b, 0x1390007c, 0x1390007f,
|
||||
0x13900080, 0x13900081, 0x13900083, 0x1390008a,
|
||||
0x1390008c, 0x1390008d, 0x13900096, 0x13900097,
|
||||
0x13900098, 0x13900099, 0x1390009a, 0x1390009f,
|
||||
0x139000a0, 0x139000a4, 0x139000a7, 0x139000a9,
|
||||
0x139000ad, 0x139000b1, 0x139000b4, 0x139000b5,
|
||||
0x139000bf, 0x139000c0, 0x139000c6, 0x139000c7,
|
||||
0x1390006e, 0x13900073, 0x13900074, 0x13900075,
|
||||
0x13900076, 0x1390007c, 0x1390007d, 0x13900080,
|
||||
0x13900081, 0x13900082, 0x13900084, 0x1390008b,
|
||||
0x1390008d, 0x1390008e, 0x13900097, 0x13900098,
|
||||
0x13900099, 0x1390009a, 0x1390009b, 0x139000a0,
|
||||
0x139000a1, 0x139000a5, 0x139000a8, 0x139000aa,
|
||||
0x139000ae, 0x139000b2, 0x139000b5, 0x139000b6,
|
||||
0x139000c0, 0x139000c1, 0x139000c7, 0x139000c8,
|
||||
// Entry C0 - DF
|
||||
0x139000ca, 0x139000cb, 0x139000cc, 0x139000ce,
|
||||
0x139000d0, 0x139000d2, 0x139000d5, 0x139000d6,
|
||||
0x139000d9, 0x139000dd, 0x139000df, 0x139000e0,
|
||||
0x139000e6, 0x139000e7, 0x139000e8, 0x139000eb,
|
||||
0x139000ec, 0x139000f0, 0x13900107, 0x13900109,
|
||||
0x1390010a, 0x1390010b, 0x1390010c, 0x1390010d,
|
||||
0x1390010e, 0x1390010f, 0x13900112, 0x13900117,
|
||||
0x1390011b, 0x1390011d, 0x1390011f, 0x13900125,
|
||||
0x139000cb, 0x139000cc, 0x139000cd, 0x139000cf,
|
||||
0x139000d1, 0x139000d3, 0x139000d6, 0x139000d7,
|
||||
0x139000da, 0x139000de, 0x139000e0, 0x139000e1,
|
||||
0x139000e7, 0x139000e8, 0x139000e9, 0x139000ec,
|
||||
0x139000ed, 0x139000f1, 0x13900108, 0x1390010a,
|
||||
0x1390010b, 0x1390010c, 0x1390010d, 0x1390010e,
|
||||
0x1390010f, 0x13900110, 0x13900113, 0x13900118,
|
||||
0x1390011c, 0x1390011e, 0x13900120, 0x13900126,
|
||||
// Entry E0 - FF
|
||||
0x13900129, 0x1390012c, 0x1390012d, 0x1390012f,
|
||||
0x13900131, 0x13900133, 0x13900135, 0x13900139,
|
||||
0x1390013c, 0x1390013d, 0x1390013f, 0x13900142,
|
||||
0x13900161, 0x13900162, 0x13900164, 0x13c00000,
|
||||
0x1390012a, 0x1390012d, 0x1390012e, 0x13900130,
|
||||
0x13900132, 0x13900134, 0x13900136, 0x1390013a,
|
||||
0x1390013d, 0x1390013e, 0x13900140, 0x13900143,
|
||||
0x13900162, 0x13900163, 0x13900165, 0x13c00000,
|
||||
0x13c00001, 0x13e00000, 0x13e0001f, 0x13e0002c,
|
||||
0x13e0003f, 0x13e00041, 0x13e00048, 0x13e00051,
|
||||
0x13e00054, 0x13e00056, 0x13e00059, 0x13e00065,
|
||||
0x13e00068, 0x13e00069, 0x13e0006e, 0x13e00086,
|
||||
0x13e00054, 0x13e00057, 0x13e0005a, 0x13e00066,
|
||||
0x13e00069, 0x13e0006a, 0x13e0006f, 0x13e00087,
|
||||
// Entry 100 - 11F
|
||||
0x13e00089, 0x13e0008f, 0x13e00094, 0x13e000cf,
|
||||
0x13e000d8, 0x13e000e2, 0x13e000e4, 0x13e000e7,
|
||||
0x13e000ec, 0x13e000f1, 0x13e0011a, 0x13e00135,
|
||||
0x13e00136, 0x13e0013b, 0x14000000, 0x1400006a,
|
||||
0x14500000, 0x1450006e, 0x14600000, 0x14600052,
|
||||
0x14800000, 0x14800024, 0x1480009c, 0x14e00000,
|
||||
0x14e00052, 0x14e00084, 0x14e000c9, 0x14e00114,
|
||||
0x15100000, 0x15100072, 0x15300000, 0x153000e7,
|
||||
0x13e0008a, 0x13e00090, 0x13e00095, 0x13e000d0,
|
||||
0x13e000d9, 0x13e000e3, 0x13e000e5, 0x13e000e8,
|
||||
0x13e000ed, 0x13e000f2, 0x13e0011b, 0x13e00136,
|
||||
0x13e00137, 0x13e0013c, 0x14000000, 0x1400006b,
|
||||
0x14500000, 0x1450006f, 0x14600000, 0x14600052,
|
||||
0x14800000, 0x14800024, 0x1480009d, 0x14e00000,
|
||||
0x14e00052, 0x14e00085, 0x14e000ca, 0x14e00115,
|
||||
0x15100000, 0x15100073, 0x15300000, 0x153000e8,
|
||||
// Entry 120 - 13F
|
||||
0x15800000, 0x15800063, 0x15800076, 0x15e00000,
|
||||
0x15800000, 0x15800064, 0x15800077, 0x15e00000,
|
||||
0x15e00036, 0x15e00037, 0x15e0003a, 0x15e0003b,
|
||||
0x15e0003c, 0x15e00049, 0x15e0004b, 0x15e0004c,
|
||||
0x15e0004d, 0x15e0004e, 0x15e0004f, 0x15e00052,
|
||||
0x15e00062, 0x15e00067, 0x15e00078, 0x15e0007a,
|
||||
0x15e0007e, 0x15e00084, 0x15e00085, 0x15e00086,
|
||||
0x15e00091, 0x15e000a8, 0x15e000b7, 0x15e000ba,
|
||||
0x15e000bb, 0x15e000be, 0x15e000bf, 0x15e000c3,
|
||||
0x15e00063, 0x15e00068, 0x15e00079, 0x15e0007b,
|
||||
0x15e0007f, 0x15e00085, 0x15e00086, 0x15e00087,
|
||||
0x15e00092, 0x15e000a9, 0x15e000b8, 0x15e000bb,
|
||||
0x15e000bc, 0x15e000bf, 0x15e000c0, 0x15e000c4,
|
||||
// Entry 140 - 15F
|
||||
0x15e000c8, 0x15e000c9, 0x15e000cc, 0x15e000d3,
|
||||
0x15e000d4, 0x15e000e5, 0x15e000ea, 0x15e00102,
|
||||
0x15e00107, 0x15e0010a, 0x15e00114, 0x15e0011c,
|
||||
0x15e00120, 0x15e00122, 0x15e00128, 0x15e0013f,
|
||||
0x15e00140, 0x15e0015f, 0x16900000, 0x1690009e,
|
||||
0x16d00000, 0x16d000d9, 0x16e00000, 0x16e00096,
|
||||
0x17e00000, 0x17e0007b, 0x19000000, 0x1900006e,
|
||||
0x1a300000, 0x1a30004e, 0x1a300078, 0x1a3000b2,
|
||||
0x15e000c9, 0x15e000ca, 0x15e000cd, 0x15e000d4,
|
||||
0x15e000d5, 0x15e000e6, 0x15e000eb, 0x15e00103,
|
||||
0x15e00108, 0x15e0010b, 0x15e00115, 0x15e0011d,
|
||||
0x15e00121, 0x15e00123, 0x15e00129, 0x15e00140,
|
||||
0x15e00141, 0x15e00160, 0x16900000, 0x1690009f,
|
||||
0x16d00000, 0x16d000da, 0x16e00000, 0x16e00097,
|
||||
0x17e00000, 0x17e0007c, 0x19000000, 0x1900006f,
|
||||
0x1a300000, 0x1a30004e, 0x1a300079, 0x1a3000b3,
|
||||
// Entry 160 - 17F
|
||||
0x1a400000, 0x1a400099, 0x1a900000, 0x1ab00000,
|
||||
0x1ab000a4, 0x1ac00000, 0x1ac00098, 0x1b400000,
|
||||
0x1b400080, 0x1b4000d4, 0x1b4000d6, 0x1b800000,
|
||||
0x1b800135, 0x1bc00000, 0x1bc00097, 0x1be00000,
|
||||
0x1be00099, 0x1d100000, 0x1d100033, 0x1d100090,
|
||||
0x1d200000, 0x1d200060, 0x1d500000, 0x1d500092,
|
||||
0x1d700000, 0x1d700028, 0x1e100000, 0x1e100095,
|
||||
0x1e700000, 0x1e7000d6, 0x1ea00000, 0x1ea00053,
|
||||
0x1a400000, 0x1a40009a, 0x1a900000, 0x1ab00000,
|
||||
0x1ab000a5, 0x1ac00000, 0x1ac00099, 0x1b400000,
|
||||
0x1b400081, 0x1b4000d5, 0x1b4000d7, 0x1b800000,
|
||||
0x1b800136, 0x1bc00000, 0x1bc00098, 0x1be00000,
|
||||
0x1be0009a, 0x1d100000, 0x1d100033, 0x1d100091,
|
||||
0x1d200000, 0x1d200061, 0x1d500000, 0x1d500093,
|
||||
0x1d700000, 0x1d700028, 0x1e100000, 0x1e100096,
|
||||
0x1e700000, 0x1e7000d7, 0x1ea00000, 0x1ea00053,
|
||||
// Entry 180 - 19F
|
||||
0x1f300000, 0x1f500000, 0x1f800000, 0x1f80009d,
|
||||
0x1f900000, 0x1f90004e, 0x1f90009e, 0x1f900113,
|
||||
0x1f900138, 0x1fa00000, 0x1fb00000, 0x20000000,
|
||||
0x200000a2, 0x20300000, 0x20700000, 0x20700052,
|
||||
0x20800000, 0x20a00000, 0x20a0012f, 0x20e00000,
|
||||
0x20f00000, 0x21000000, 0x2100007d, 0x21200000,
|
||||
0x21200067, 0x21600000, 0x21700000, 0x217000a4,
|
||||
0x21f00000, 0x22300000, 0x2230012f, 0x22700000,
|
||||
0x1f300000, 0x1f500000, 0x1f800000, 0x1f80009e,
|
||||
0x1f900000, 0x1f90004e, 0x1f90009f, 0x1f900114,
|
||||
0x1f900139, 0x1fa00000, 0x1fb00000, 0x20000000,
|
||||
0x200000a3, 0x20300000, 0x20700000, 0x20700052,
|
||||
0x20800000, 0x20a00000, 0x20a00130, 0x20e00000,
|
||||
0x20f00000, 0x21000000, 0x2100007e, 0x21200000,
|
||||
0x21200068, 0x21600000, 0x21700000, 0x217000a5,
|
||||
0x21f00000, 0x22300000, 0x22300130, 0x22700000,
|
||||
// Entry 1A0 - 1BF
|
||||
0x2270005a, 0x23400000, 0x234000c3, 0x23900000,
|
||||
0x239000a4, 0x24200000, 0x242000ae, 0x24400000,
|
||||
0x24400052, 0x24500000, 0x24500082, 0x24600000,
|
||||
0x246000a4, 0x24a00000, 0x24a000a6, 0x25100000,
|
||||
0x25100099, 0x25400000, 0x254000aa, 0x254000ab,
|
||||
0x25600000, 0x25600099, 0x26a00000, 0x26a00099,
|
||||
0x26b00000, 0x26b0012f, 0x26d00000, 0x26d00052,
|
||||
0x26e00000, 0x26e00060, 0x27400000, 0x28100000,
|
||||
0x2270005b, 0x23400000, 0x234000c4, 0x23900000,
|
||||
0x239000a5, 0x24200000, 0x242000af, 0x24400000,
|
||||
0x24400052, 0x24500000, 0x24500083, 0x24600000,
|
||||
0x246000a5, 0x24a00000, 0x24a000a7, 0x25100000,
|
||||
0x2510009a, 0x25400000, 0x254000ab, 0x254000ac,
|
||||
0x25600000, 0x2560009a, 0x26a00000, 0x26a0009a,
|
||||
0x26b00000, 0x26b00130, 0x26d00000, 0x26d00052,
|
||||
0x26e00000, 0x26e00061, 0x27400000, 0x28100000,
|
||||
// Entry 1C0 - 1DF
|
||||
0x2810007b, 0x28a00000, 0x28a000a5, 0x29100000,
|
||||
0x2910012f, 0x29500000, 0x295000b7, 0x2a300000,
|
||||
0x2a300131, 0x2af00000, 0x2af00135, 0x2b500000,
|
||||
0x2810007c, 0x28a00000, 0x28a000a6, 0x29100000,
|
||||
0x29100130, 0x29500000, 0x295000b8, 0x2a300000,
|
||||
0x2a300132, 0x2af00000, 0x2af00136, 0x2b500000,
|
||||
0x2b50002a, 0x2b50004b, 0x2b50004c, 0x2b50004d,
|
||||
0x2b800000, 0x2b8000af, 0x2bf00000, 0x2bf0009b,
|
||||
0x2bf0009c, 0x2c000000, 0x2c0000b6, 0x2c200000,
|
||||
0x2c20004b, 0x2c400000, 0x2c4000a4, 0x2c500000,
|
||||
0x2c5000a4, 0x2c700000, 0x2c7000b8, 0x2d100000,
|
||||
0x2b800000, 0x2b8000b0, 0x2bf00000, 0x2bf0009c,
|
||||
0x2bf0009d, 0x2c000000, 0x2c0000b7, 0x2c200000,
|
||||
0x2c20004b, 0x2c400000, 0x2c4000a5, 0x2c500000,
|
||||
0x2c5000a5, 0x2c700000, 0x2c7000b9, 0x2d100000,
|
||||
// Entry 1E0 - 1FF
|
||||
0x2d1000a4, 0x2d10012f, 0x2e900000, 0x2e9000a4,
|
||||
0x2ed00000, 0x2ed000cc, 0x2f100000, 0x2f1000bf,
|
||||
0x2f200000, 0x2f2000d1, 0x2f400000, 0x2f400052,
|
||||
0x2ff00000, 0x2ff000c2, 0x30400000, 0x30400099,
|
||||
0x30b00000, 0x30b000c5, 0x31000000, 0x31b00000,
|
||||
0x31b00099, 0x31f00000, 0x31f0003e, 0x31f000d0,
|
||||
0x31f0010d, 0x32000000, 0x320000cb, 0x32500000,
|
||||
0x32500052, 0x33100000, 0x331000c4, 0x33a00000,
|
||||
0x2d1000a5, 0x2d100130, 0x2e900000, 0x2e9000a5,
|
||||
0x2ed00000, 0x2ed000cd, 0x2f100000, 0x2f1000c0,
|
||||
0x2f200000, 0x2f2000d2, 0x2f400000, 0x2f400052,
|
||||
0x2ff00000, 0x2ff000c3, 0x30400000, 0x3040009a,
|
||||
0x30b00000, 0x30b000c6, 0x31000000, 0x31b00000,
|
||||
0x31b0009a, 0x31f00000, 0x31f0003e, 0x31f000d1,
|
||||
0x31f0010e, 0x32000000, 0x320000cc, 0x32500000,
|
||||
0x32500052, 0x33100000, 0x331000c5, 0x33a00000,
|
||||
// Entry 200 - 21F
|
||||
0x33a0009c, 0x34100000, 0x34500000, 0x345000d2,
|
||||
0x34700000, 0x347000da, 0x34700110, 0x34e00000,
|
||||
0x34e00164, 0x35000000, 0x35000060, 0x350000d9,
|
||||
0x35100000, 0x35100099, 0x351000db, 0x36700000,
|
||||
0x36700030, 0x36700036, 0x36700040, 0x3670005b,
|
||||
0x367000d9, 0x36700116, 0x3670011b, 0x36800000,
|
||||
0x36800052, 0x36a00000, 0x36a000da, 0x36c00000,
|
||||
0x33a0009d, 0x34100000, 0x34500000, 0x345000d3,
|
||||
0x34700000, 0x347000db, 0x34700111, 0x34e00000,
|
||||
0x34e00165, 0x35000000, 0x35000061, 0x350000da,
|
||||
0x35100000, 0x3510009a, 0x351000dc, 0x36700000,
|
||||
0x36700030, 0x36700036, 0x36700040, 0x3670005c,
|
||||
0x367000da, 0x36700117, 0x3670011c, 0x36800000,
|
||||
0x36800052, 0x36a00000, 0x36a000db, 0x36c00000,
|
||||
0x36c00052, 0x36f00000, 0x37500000, 0x37600000,
|
||||
// Entry 220 - 23F
|
||||
0x37a00000, 0x38000000, 0x38000117, 0x38700000,
|
||||
0x38900000, 0x38900131, 0x39000000, 0x3900006f,
|
||||
0x390000a4, 0x39500000, 0x39500099, 0x39800000,
|
||||
0x3980007d, 0x39800106, 0x39d00000, 0x39d05000,
|
||||
0x39d050e8, 0x39d36000, 0x39d36099, 0x3a100000,
|
||||
0x3b300000, 0x3b3000e9, 0x3bd00000, 0x3bd00001,
|
||||
0x37a00000, 0x38000000, 0x38000118, 0x38700000,
|
||||
0x38900000, 0x38900132, 0x39000000, 0x39000070,
|
||||
0x390000a5, 0x39500000, 0x3950009a, 0x39800000,
|
||||
0x3980007e, 0x39800107, 0x39d00000, 0x39d05000,
|
||||
0x39d050e9, 0x39d36000, 0x39d3609a, 0x3a100000,
|
||||
0x3b300000, 0x3b3000ea, 0x3bd00000, 0x3bd00001,
|
||||
0x3be00000, 0x3be00024, 0x3c000000, 0x3c00002a,
|
||||
0x3c000041, 0x3c00004e, 0x3c00005a, 0x3c000086,
|
||||
0x3c000041, 0x3c00004e, 0x3c00005b, 0x3c000087,
|
||||
// Entry 240 - 25F
|
||||
0x3c00008b, 0x3c0000b7, 0x3c0000c6, 0x3c0000d1,
|
||||
0x3c0000ee, 0x3c000118, 0x3c000126, 0x3c400000,
|
||||
0x3c40003f, 0x3c400069, 0x3c4000e4, 0x3d400000,
|
||||
0x3c00008c, 0x3c0000b8, 0x3c0000c7, 0x3c0000d2,
|
||||
0x3c0000ef, 0x3c000119, 0x3c000127, 0x3c400000,
|
||||
0x3c40003f, 0x3c40006a, 0x3c4000e5, 0x3d400000,
|
||||
0x3d40004e, 0x3d900000, 0x3d90003a, 0x3dc00000,
|
||||
0x3dc000bc, 0x3dc00104, 0x3de00000, 0x3de0012f,
|
||||
0x3e200000, 0x3e200047, 0x3e2000a5, 0x3e2000ae,
|
||||
0x3e2000bc, 0x3e200106, 0x3e200130, 0x3e500000,
|
||||
0x3e500107, 0x3e600000, 0x3e60012f, 0x3eb00000,
|
||||
0x3dc000bd, 0x3dc00105, 0x3de00000, 0x3de00130,
|
||||
0x3e200000, 0x3e200047, 0x3e2000a6, 0x3e2000af,
|
||||
0x3e2000bd, 0x3e200107, 0x3e200131, 0x3e500000,
|
||||
0x3e500108, 0x3e600000, 0x3e600130, 0x3eb00000,
|
||||
// Entry 260 - 27F
|
||||
0x3eb00106, 0x3ec00000, 0x3ec000a4, 0x3f300000,
|
||||
0x3f30012f, 0x3fa00000, 0x3fa000e8, 0x3fc00000,
|
||||
0x3fd00000, 0x3fd00072, 0x3fd000da, 0x3fd0010c,
|
||||
0x3ff00000, 0x3ff000d1, 0x40100000, 0x401000c3,
|
||||
0x3eb00107, 0x3ec00000, 0x3ec000a5, 0x3f300000,
|
||||
0x3f300130, 0x3fa00000, 0x3fa000e9, 0x3fc00000,
|
||||
0x3fd00000, 0x3fd00073, 0x3fd000db, 0x3fd0010d,
|
||||
0x3ff00000, 0x3ff000d2, 0x40100000, 0x401000c4,
|
||||
0x40200000, 0x4020004c, 0x40700000, 0x40800000,
|
||||
0x4085a000, 0x4085a0ba, 0x408e8000, 0x408e80ba,
|
||||
0x40c00000, 0x40c000b3, 0x41200000, 0x41200111,
|
||||
0x41600000, 0x4160010f, 0x41c00000, 0x41d00000,
|
||||
0x4085b000, 0x4085b0bb, 0x408eb000, 0x408eb0bb,
|
||||
0x40c00000, 0x40c000b4, 0x41200000, 0x41200112,
|
||||
0x41600000, 0x41600110, 0x41c00000, 0x41d00000,
|
||||
// Entry 280 - 29F
|
||||
0x41e00000, 0x41f00000, 0x41f00072, 0x42200000,
|
||||
0x42300000, 0x42300164, 0x42900000, 0x42900062,
|
||||
0x4290006f, 0x429000a4, 0x42900115, 0x43100000,
|
||||
0x43100027, 0x431000c2, 0x4310014d, 0x43200000,
|
||||
0x43220000, 0x43220033, 0x432200bd, 0x43220105,
|
||||
0x4322014d, 0x4325a000, 0x4325a033, 0x4325a0bd,
|
||||
0x4325a105, 0x4325a14d, 0x43700000, 0x43a00000,
|
||||
0x43b00000, 0x44400000, 0x44400031, 0x44400072,
|
||||
0x41e00000, 0x41f00000, 0x41f00073, 0x42200000,
|
||||
0x42300000, 0x42300165, 0x42900000, 0x42900063,
|
||||
0x42900070, 0x429000a5, 0x42900116, 0x43100000,
|
||||
0x43100027, 0x431000c3, 0x4310014e, 0x43200000,
|
||||
0x43220000, 0x43220033, 0x432200be, 0x43220106,
|
||||
0x4322014e, 0x4325b000, 0x4325b033, 0x4325b0be,
|
||||
0x4325b106, 0x4325b14e, 0x43700000, 0x43a00000,
|
||||
0x43b00000, 0x44400000, 0x44400031, 0x44400073,
|
||||
// Entry 2A0 - 2BF
|
||||
0x4440010c, 0x44500000, 0x4450004b, 0x445000a4,
|
||||
0x4450012f, 0x44500131, 0x44e00000, 0x45000000,
|
||||
0x45000099, 0x450000b3, 0x450000d0, 0x4500010d,
|
||||
0x46100000, 0x46100099, 0x46400000, 0x464000a4,
|
||||
0x46400131, 0x46700000, 0x46700124, 0x46b00000,
|
||||
0x46b00123, 0x46f00000, 0x46f0006d, 0x46f0006f,
|
||||
0x47100000, 0x47600000, 0x47600127, 0x47a00000,
|
||||
0x48000000, 0x48200000, 0x48200129, 0x48a00000,
|
||||
0x4440010d, 0x44500000, 0x4450004b, 0x445000a5,
|
||||
0x44500130, 0x44500132, 0x44e00000, 0x45000000,
|
||||
0x4500009a, 0x450000b4, 0x450000d1, 0x4500010e,
|
||||
0x46100000, 0x4610009a, 0x46400000, 0x464000a5,
|
||||
0x46400132, 0x46700000, 0x46700125, 0x46b00000,
|
||||
0x46b00124, 0x46f00000, 0x46f0006e, 0x46f00070,
|
||||
0x47100000, 0x47600000, 0x47600128, 0x47a00000,
|
||||
0x48000000, 0x48200000, 0x4820012a, 0x48a00000,
|
||||
// Entry 2C0 - 2DF
|
||||
0x48a0005d, 0x48a0012b, 0x48e00000, 0x49400000,
|
||||
0x49400106, 0x4a400000, 0x4a4000d4, 0x4a900000,
|
||||
0x4a9000ba, 0x4ac00000, 0x4ac00053, 0x4ae00000,
|
||||
0x4ae00130, 0x4b400000, 0x4b400099, 0x4b4000e8,
|
||||
0x48a0005e, 0x48a0012c, 0x48e00000, 0x49400000,
|
||||
0x49400107, 0x4a400000, 0x4a4000d5, 0x4a900000,
|
||||
0x4a9000bb, 0x4ac00000, 0x4ac00053, 0x4ae00000,
|
||||
0x4ae00131, 0x4b400000, 0x4b40009a, 0x4b4000e9,
|
||||
0x4bc00000, 0x4bc05000, 0x4bc05024, 0x4bc20000,
|
||||
0x4bc20137, 0x4bc5a000, 0x4bc5a137, 0x4be00000,
|
||||
0x4be5a000, 0x4be5a0b4, 0x4bef1000, 0x4bef10b4,
|
||||
0x4c000000, 0x4c300000, 0x4c30013e, 0x4c900000,
|
||||
0x4bc20138, 0x4bc5b000, 0x4bc5b138, 0x4be00000,
|
||||
0x4be5b000, 0x4be5b0b5, 0x4bef4000, 0x4bef40b5,
|
||||
0x4c000000, 0x4c300000, 0x4c30013f, 0x4c900000,
|
||||
// Entry 2E0 - 2FF
|
||||
0x4c900001, 0x4cc00000, 0x4cc0012f, 0x4ce00000,
|
||||
0x4cf00000, 0x4cf0004e, 0x4e500000, 0x4e500114,
|
||||
0x4f200000, 0x4fb00000, 0x4fb00131, 0x50900000,
|
||||
0x4c900001, 0x4cc00000, 0x4cc00130, 0x4ce00000,
|
||||
0x4cf00000, 0x4cf0004e, 0x4e500000, 0x4e500115,
|
||||
0x4f200000, 0x4fb00000, 0x4fb00132, 0x50900000,
|
||||
0x50900052, 0x51200000, 0x51200001, 0x51800000,
|
||||
0x5180003b, 0x518000d6, 0x51f00000, 0x51f3b000,
|
||||
0x51f3b053, 0x51f3c000, 0x51f3c08d, 0x52800000,
|
||||
0x528000ba, 0x52900000, 0x5293b000, 0x5293b053,
|
||||
0x5293b08d, 0x5293b0c6, 0x5293b10d, 0x5293c000,
|
||||
0x5180003b, 0x518000d7, 0x51f00000, 0x51f3b000,
|
||||
0x51f3b053, 0x51f3c000, 0x51f3c08e, 0x52800000,
|
||||
0x528000bb, 0x52900000, 0x5293b000, 0x5293b053,
|
||||
0x5293b08e, 0x5293b0c7, 0x5293b10e, 0x5293c000,
|
||||
// Entry 300 - 31F
|
||||
0x5293c08d, 0x5293c0c6, 0x5293c12e, 0x52f00000,
|
||||
0x52f00161,
|
||||
0x5293c08e, 0x5293c0c7, 0x5293c12f, 0x52f00000,
|
||||
0x52f00162,
|
||||
} // Size: 3116 bytes
|
||||
|
||||
const specialTagsStr string = "ca-ES-valencia en-US-u-va-posix"
|
||||
|
||||
// Total table size 3147 bytes (3KiB); checksum: 6772C83C
|
||||
// Total table size 3147 bytes (3KiB); checksum: 5A8FFFA5
|
||||
|
||||
4682
vendor/golang.org/x/text/internal/language/tables.go
generated
vendored
4682
vendor/golang.org/x/text/internal/language/tables.go
generated
vendored
File diff suppressed because it is too large
Load Diff
2
vendor/golang.org/x/text/language/match.go
generated
vendored
2
vendor/golang.org/x/text/language/match.go
generated
vendored
@@ -434,7 +434,7 @@ func newMatcher(supported []Tag, options []MatchOption) *matcher {
|
||||
// (their canonicalization simply substitutes a different language code, but
|
||||
// nothing else), the match confidence is Exact, otherwise it is High.
|
||||
for i, lm := range language.AliasMap {
|
||||
// If deprecated codes match and there is no fiddling with the script or
|
||||
// If deprecated codes match and there is no fiddling with the script
|
||||
// or region, we consider it an exact match.
|
||||
conf := Exact
|
||||
if language.AliasTypes[i] != language.Macro {
|
||||
|
||||
146
vendor/golang.org/x/text/language/tables.go
generated
vendored
146
vendor/golang.org/x/text/language/tables.go
generated
vendored
@@ -23,31 +23,31 @@ const (
|
||||
_419 = 31
|
||||
_BR = 65
|
||||
_CA = 73
|
||||
_ES = 110
|
||||
_GB = 123
|
||||
_MD = 188
|
||||
_PT = 238
|
||||
_UK = 306
|
||||
_US = 309
|
||||
_ZZ = 357
|
||||
_XA = 323
|
||||
_XC = 325
|
||||
_XK = 333
|
||||
_ES = 111
|
||||
_GB = 124
|
||||
_MD = 189
|
||||
_PT = 239
|
||||
_UK = 307
|
||||
_US = 310
|
||||
_ZZ = 358
|
||||
_XA = 324
|
||||
_XC = 326
|
||||
_XK = 334
|
||||
)
|
||||
const (
|
||||
_Latn = 90
|
||||
_Latn = 91
|
||||
_Hani = 57
|
||||
_Hans = 59
|
||||
_Hant = 60
|
||||
_Qaaa = 147
|
||||
_Qaai = 155
|
||||
_Qabx = 196
|
||||
_Zinh = 252
|
||||
_Zyyy = 257
|
||||
_Zzzz = 258
|
||||
_Qaaa = 149
|
||||
_Qaai = 157
|
||||
_Qabx = 198
|
||||
_Zinh = 255
|
||||
_Zyyy = 260
|
||||
_Zzzz = 261
|
||||
)
|
||||
|
||||
var regionToGroups = []uint8{ // 358 elements
|
||||
var regionToGroups = []uint8{ // 359 elements
|
||||
// Entry 0 - 3F
|
||||
0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
|
||||
@@ -60,51 +60,51 @@ var regionToGroups = []uint8{ // 358 elements
|
||||
// Entry 40 - 7F
|
||||
0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
|
||||
0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x08,
|
||||
0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00,
|
||||
// Entry 80 - BF
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x04, 0x01, 0x00, 0x04, 0x02, 0x00, 0x04,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
// Entry C0 - FF
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01,
|
||||
0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00,
|
||||
0x08, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04,
|
||||
// Entry 80 - BF
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x04, 0x01, 0x00, 0x04, 0x02, 0x00,
|
||||
0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00, 0x04,
|
||||
// Entry C0 - FF
|
||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
||||
0x01, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x05, 0x00, 0x00,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
// Entry 100 - 13F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
|
||||
0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04, 0x00,
|
||||
0x00, 0x04, 0x00, 0x04, 0x04, 0x05, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
|
||||
0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x05, 0x04,
|
||||
0x00, 0x00, 0x04, 0x00, 0x04, 0x04, 0x05, 0x00,
|
||||
// Entry 140 - 17F
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
} // Size: 382 bytes
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
} // Size: 383 bytes
|
||||
|
||||
var paradigmLocales = [][3]uint16{ // 3 elements
|
||||
0: [3]uint16{0x139, 0x0, 0x7b},
|
||||
0: [3]uint16{0x139, 0x0, 0x7c},
|
||||
1: [3]uint16{0x13e, 0x0, 0x1f},
|
||||
2: [3]uint16{0x3c0, 0x41, 0xee},
|
||||
2: [3]uint16{0x3c0, 0x41, 0xef},
|
||||
} // Size: 42 bytes
|
||||
|
||||
type mutualIntelligibility struct {
|
||||
@@ -249,30 +249,30 @@ var matchLang = []mutualIntelligibility{ // 113 elements
|
||||
// matchScript holds pairs of scriptIDs where readers of one script
|
||||
// can typically also read the other. Each is associated with a confidence.
|
||||
var matchScript = []scriptIntelligibility{ // 26 elements
|
||||
0: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x5a, haveScript: 0x20, distance: 0x5},
|
||||
1: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x20, haveScript: 0x5a, distance: 0x5},
|
||||
2: {wantLang: 0x58, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
|
||||
3: {wantLang: 0xa5, haveLang: 0x139, wantScript: 0xe, haveScript: 0x5a, distance: 0xa},
|
||||
0: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x5b, haveScript: 0x20, distance: 0x5},
|
||||
1: {wantLang: 0x432, haveLang: 0x432, wantScript: 0x20, haveScript: 0x5b, distance: 0x5},
|
||||
2: {wantLang: 0x58, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
|
||||
3: {wantLang: 0xa5, haveLang: 0x139, wantScript: 0xe, haveScript: 0x5b, distance: 0xa},
|
||||
4: {wantLang: 0x1d7, haveLang: 0x3e2, wantScript: 0x8, haveScript: 0x20, distance: 0xa},
|
||||
5: {wantLang: 0x210, haveLang: 0x139, wantScript: 0x2e, haveScript: 0x5a, distance: 0xa},
|
||||
6: {wantLang: 0x24a, haveLang: 0x139, wantScript: 0x4e, haveScript: 0x5a, distance: 0xa},
|
||||
7: {wantLang: 0x251, haveLang: 0x139, wantScript: 0x52, haveScript: 0x5a, distance: 0xa},
|
||||
8: {wantLang: 0x2b8, haveLang: 0x139, wantScript: 0x57, haveScript: 0x5a, distance: 0xa},
|
||||
9: {wantLang: 0x304, haveLang: 0x139, wantScript: 0x6e, haveScript: 0x5a, distance: 0xa},
|
||||
10: {wantLang: 0x331, haveLang: 0x139, wantScript: 0x75, haveScript: 0x5a, distance: 0xa},
|
||||
11: {wantLang: 0x351, haveLang: 0x139, wantScript: 0x22, haveScript: 0x5a, distance: 0xa},
|
||||
12: {wantLang: 0x395, haveLang: 0x139, wantScript: 0x81, haveScript: 0x5a, distance: 0xa},
|
||||
13: {wantLang: 0x39d, haveLang: 0x139, wantScript: 0x36, haveScript: 0x5a, distance: 0xa},
|
||||
14: {wantLang: 0x3be, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
|
||||
15: {wantLang: 0x3fa, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
|
||||
16: {wantLang: 0x40c, haveLang: 0x139, wantScript: 0xd4, haveScript: 0x5a, distance: 0xa},
|
||||
17: {wantLang: 0x450, haveLang: 0x139, wantScript: 0xe3, haveScript: 0x5a, distance: 0xa},
|
||||
18: {wantLang: 0x461, haveLang: 0x139, wantScript: 0xe6, haveScript: 0x5a, distance: 0xa},
|
||||
19: {wantLang: 0x46f, haveLang: 0x139, wantScript: 0x2c, haveScript: 0x5a, distance: 0xa},
|
||||
20: {wantLang: 0x476, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
|
||||
21: {wantLang: 0x4b4, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5a, distance: 0xa},
|
||||
22: {wantLang: 0x4bc, haveLang: 0x3e2, wantScript: 0x5a, haveScript: 0x20, distance: 0xa},
|
||||
23: {wantLang: 0x512, haveLang: 0x139, wantScript: 0x3e, haveScript: 0x5a, distance: 0xa},
|
||||
5: {wantLang: 0x210, haveLang: 0x139, wantScript: 0x2e, haveScript: 0x5b, distance: 0xa},
|
||||
6: {wantLang: 0x24a, haveLang: 0x139, wantScript: 0x4f, haveScript: 0x5b, distance: 0xa},
|
||||
7: {wantLang: 0x251, haveLang: 0x139, wantScript: 0x53, haveScript: 0x5b, distance: 0xa},
|
||||
8: {wantLang: 0x2b8, haveLang: 0x139, wantScript: 0x58, haveScript: 0x5b, distance: 0xa},
|
||||
9: {wantLang: 0x304, haveLang: 0x139, wantScript: 0x6f, haveScript: 0x5b, distance: 0xa},
|
||||
10: {wantLang: 0x331, haveLang: 0x139, wantScript: 0x76, haveScript: 0x5b, distance: 0xa},
|
||||
11: {wantLang: 0x351, haveLang: 0x139, wantScript: 0x22, haveScript: 0x5b, distance: 0xa},
|
||||
12: {wantLang: 0x395, haveLang: 0x139, wantScript: 0x83, haveScript: 0x5b, distance: 0xa},
|
||||
13: {wantLang: 0x39d, haveLang: 0x139, wantScript: 0x36, haveScript: 0x5b, distance: 0xa},
|
||||
14: {wantLang: 0x3be, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
|
||||
15: {wantLang: 0x3fa, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
|
||||
16: {wantLang: 0x40c, haveLang: 0x139, wantScript: 0xd6, haveScript: 0x5b, distance: 0xa},
|
||||
17: {wantLang: 0x450, haveLang: 0x139, wantScript: 0xe6, haveScript: 0x5b, distance: 0xa},
|
||||
18: {wantLang: 0x461, haveLang: 0x139, wantScript: 0xe9, haveScript: 0x5b, distance: 0xa},
|
||||
19: {wantLang: 0x46f, haveLang: 0x139, wantScript: 0x2c, haveScript: 0x5b, distance: 0xa},
|
||||
20: {wantLang: 0x476, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
|
||||
21: {wantLang: 0x4b4, haveLang: 0x139, wantScript: 0x5, haveScript: 0x5b, distance: 0xa},
|
||||
22: {wantLang: 0x4bc, haveLang: 0x3e2, wantScript: 0x5b, haveScript: 0x20, distance: 0xa},
|
||||
23: {wantLang: 0x512, haveLang: 0x139, wantScript: 0x3e, haveScript: 0x5b, distance: 0xa},
|
||||
24: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3b, haveScript: 0x3c, distance: 0xf},
|
||||
25: {wantLang: 0x529, haveLang: 0x529, wantScript: 0x3c, haveScript: 0x3b, distance: 0x13},
|
||||
} // Size: 232 bytes
|
||||
@@ -295,4 +295,4 @@ var matchRegion = []regionIntelligibility{ // 15 elements
|
||||
14: {lang: 0x529, script: 0x3c, group: 0x80, distance: 0x5},
|
||||
} // Size: 114 bytes
|
||||
|
||||
// Total table size 1472 bytes (1KiB); checksum: F86C669
|
||||
// Total table size 1473 bytes (1KiB); checksum: 7BB90B5C
|
||||
|
||||
13
vendor/modules.txt
vendored
13
vendor/modules.txt
vendored
@@ -1,17 +1,16 @@
|
||||
# github.com/mattn/go-sqlite3 v1.14.7
|
||||
## explicit; go 1.12
|
||||
github.com/mattn/go-sqlite3
|
||||
# golang.org/x/net v0.8.0
|
||||
## explicit; go 1.17
|
||||
# golang.org/x/net v0.33.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/net/html
|
||||
golang.org/x/net/html/atom
|
||||
golang.org/x/net/html/charset
|
||||
# golang.org/x/sys v0.6.0
|
||||
## explicit; go 1.17
|
||||
golang.org/x/sys/internal/unsafeheader
|
||||
# golang.org/x/sys v0.28.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/sys/windows
|
||||
# golang.org/x/text v0.8.0
|
||||
## explicit; go 1.17
|
||||
# golang.org/x/text v0.21.0
|
||||
## explicit; go 1.18
|
||||
golang.org/x/text/encoding
|
||||
golang.org/x/text/encoding/charmap
|
||||
golang.org/x/text/encoding/htmlindex
|
||||
|
||||
Reference in New Issue
Block a user