From 4d6c35443655156d8e717d7216df632e5ef04e1f Mon Sep 17 00:00:00 2001 From: Roman Baeriswyl Date: Sun, 26 Oct 2025 16:22:50 +0100 Subject: [PATCH] Initial commit --- go.mod | 58 +++++++ go.sum | 177 +++++++++++++++++++++ main.go | 32 ++++ main_releases.go | 28 ++++ task_pack_release/compress.go | 108 +++++++++++++ task_pack_release/info.nfo.tmpl | 50 ++++++ task_pack_release/nfo.go | 272 ++++++++++++++++++++++++++++++++ task_pack_release/task.go | 13 ++ task_pack_release/utils.go | 18 +++ tasks/black-border-analyze.go | 185 ++++++++++++++++++++++ tasks/epic-link.go | 89 +++++++++++ tasks/mega-account.go | 163 +++++++++++++++++++ 12 files changed, 1193 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 main_releases.go create mode 100644 task_pack_release/compress.go create mode 100644 task_pack_release/info.nfo.tmpl create mode 100644 task_pack_release/nfo.go create mode 100644 task_pack_release/task.go create mode 100644 task_pack_release/utils.go create mode 100644 tasks/black-border-analyze.go create mode 100644 tasks/epic-link.go create mode 100644 tasks/mega-account.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2c3b4e7 --- /dev/null +++ b/go.mod @@ -0,0 +1,58 @@ +module varia-go + +go 1.25.2 + +require ( + github.com/roemer/goext v0.8.0 + github.com/roemer/gotaskr v0.7.0 +) + +require ( + dario.cat/mergo v1.0.1 // indirect + github.com/CycloneDX/cyclonedx-go v0.9.2 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProtonMail/go-crypto v1.1.6 // indirect + github.com/andybalholm/brotli v1.1.1 // indirect + github.com/cloudflare/circl v1.6.1 // indirect + github.com/cyphar/filepath-securejoin v0.4.1 // indirect + github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fatih/color v1.18.0 // indirect + github.com/forPelevin/gomoji v1.3.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.6.2 // indirect + github.com/go-git/go-git/v5 v5.14.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/gookit/color v1.5.4 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jfrog/archiver/v3 v3.6.1 // indirect + github.com/jfrog/build-info-go v1.10.17 // indirect + github.com/jfrog/gofrog v1.7.6 // indirect + github.com/jfrog/jfrog-client-go v1.54.7 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect + github.com/klauspost/pgzip v1.2.6 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/minio/sha256-simd v1.0.1 // indirect + github.com/nwaples/rardecode v1.1.3 // indirect + github.com/pierrec/lz4/v4 v4.1.22 // indirect + github.com/pjbgf/sha1cd v0.3.2 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/skeema/knownhosts v1.3.1 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect + golang.org/x/crypto v0.36.0 // indirect + golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..afaab13 --- /dev/null +++ b/go.sum @@ -0,0 +1,177 @@ +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +github.com/CycloneDX/cyclonedx-go v0.9.2 h1:688QHn2X/5nRezKe2ueIVCt+NRqf7fl3AVQk+vaFcIo= +github.com/CycloneDX/cyclonedx-go v0.9.2/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= +github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= +github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= +github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= +github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= +github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= +github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= +github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= +github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/forPelevin/gomoji v1.3.0 h1:WPIOLWB1bvRYlKZnSSEevLt3IfKlLs+tK+YA9fFYlkE= +github.com/forPelevin/gomoji v1.3.0/go.mod h1:mM6GtmCgpoQP2usDArc6GjbXrti5+FffolyQfGgPboQ= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= +github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= +github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= +github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jfrog/archiver/v3 v3.6.1 h1:LOxnkw9pOn45DzCbZNFV6K0+6dCsQ0L8mR3ZcujO5eI= +github.com/jfrog/archiver/v3 v3.6.1/go.mod h1:VgR+3WZS4N+i9FaDwLZbq+jeU4B4zctXL+gL4EMzfLw= +github.com/jfrog/build-info-go v1.10.17 h1:wnVd9KkyFGQgNL+oU1wXyJB7/Ui9O/MqUnNKUMsyoRw= +github.com/jfrog/build-info-go v1.10.17/go.mod h1:szdz9+WzB7+7PGnILLUgyY+OF5qD5geBT7UGNIxibyw= +github.com/jfrog/gofrog v1.7.6 h1:QmfAiRzVyaI7JYGsB7cxfAJePAZTzFz0gRWZSE27c6s= +github.com/jfrog/gofrog v1.7.6/go.mod h1:ntr1txqNOZtHplmaNd7rS4f8jpA5Apx8em70oYEe7+4= +github.com/jfrog/jfrog-client-go v1.54.7 h1:S1geo9T5ZCAb7EkXSv+NJ0K8+yhDsxlrybHTosCilIg= +github.com/jfrog/jfrog-client-go v1.54.7/go.mod h1:cOy7Pn34bGtjp0eWHADTRJG5Er0qVnJIz04u+NGEpcQ= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= +github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY= +github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8= +github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= +github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= +github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= +github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9lEc= +github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= +github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= +github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/roemer/goext v0.8.0 h1:gdx2gjDAq1nshbvFSrqR/wA2CzLLJlJEgc/DfdYhQTQ= +github.com/roemer/goext v0.8.0/go.mod h1:D+HvjseqdlevkQ9QeCME6XvXoUfJwmlyRrY3YfmTnB8= +github.com/roemer/gotaskr v0.7.0 h1:zP2SOVJAV4yGdItmEIYjYxgXF8gzmX+y8a6tnbXOz0o= +github.com/roemer/gotaskr v0.7.0/go.mod h1:ue5tvkLn9BG8i41JogicOxS5rYqJlbHW8Hst9VXxliA= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= +github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= +github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= +github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= +github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= +golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go new file mode 100644 index 0000000..c550c80 --- /dev/null +++ b/main.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "os" + "varia-go/tasks" + + "github.com/roemer/gotaskr" +) + +func main() { + os.Exit(gotaskr.Execute()) +} + +func init() { + gotaskr.Task("Epic-Links", func() error { + return (&tasks.EpicLinkTask{}).Run() + }) + + gotaskr.Task("Create-Mega-Account", func() error { + return (&tasks.MegaAccountTask{}).Run() + }) + + // args: --folder=\\nas03\Dump + gotaskr.Task("Black-Border-Analyze", func() error { + folder, hasArg := gotaskr.GetArgument("folder") + if !hasArg { + return fmt.Errorf("folder argument is required") + } + return tasks.NewBlackBorderAnalyzeTask("blackborder.log").Run(folder) + }) +} diff --git a/main_releases.go b/main_releases.go new file mode 100644 index 0000000..1a39fb2 --- /dev/null +++ b/main_releases.go @@ -0,0 +1,28 @@ +package main + +import ( + "time" + "varia-go/task_pack_release" + + "github.com/roemer/gotaskr" +) + +func init() { + gotaskr.Task("Jimmy-Neutron-Extra", func() error { + return task_pack_release.PackRelease( + `\\nas03\storage\_Incoming\_Reencode\The Adventures of Jimmy Neutron\_enc\Extras\Jimmy Neutron - S01E00 - Pilotfolge - Runaway Rocketboy.mkv`, + `F:\jim\extra_2`, "jim-extra", "serienfans.org", "500m", + &task_pack_release.NfoCreatorSettings{ + Title: task_pack_release.NewTitleBuilder("Jimmy.Neutron.S01E00.Pilot.Runaway.Rocketboy").DVDRip().X264().Build(), + Infos: []*task_pack_release.KeyValue{ + {"Release Date", time.Now().Format(time.DateOnly)}, + {"Source", task_pack_release.Dvd}, + {"Subs", "German"}, + {"Video", "768x576"}, + {"Audio 1", "English"}, + }, + Notes: "Degrained, sharpened, cropped.", + }, + ) + }) +} diff --git a/task_pack_release/compress.go b/task_pack_release/compress.go new file mode 100644 index 0000000..f323109 --- /dev/null +++ b/task_pack_release/compress.go @@ -0,0 +1,108 @@ +package task_pack_release + +import ( + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" +) + +var rarPath = `C:\Program Files\WinRAR\WinRAR.exe` + +func compress(srcPath string, dstPath string, releaseName string, archivePwd string, archiveSize string, nfoFilePath string) error { + // Check if the content is a directory or a single file + fi, err := os.Stat(srcPath) + if err != nil { + return fmt.Errorf("failed to stat content path: %w", err) + } + + // Collect the files to be archived + var files []string + if fi.IsDir() { + dirEntries, err := os.ReadDir(srcPath) + if err != nil { + return fmt.Errorf("failed to read directory: %w", err) + } + for _, entry := range dirEntries { + if entry.IsDir() { + continue + } + filePath := filepath.Join(srcPath, entry.Name()) + if filepath.Ext(filePath) != ".nfo" { + files = append(files, filePath) + } + } + } else { + files = append(files, srcPath) + } + + os.MkdirAll(dstPath, os.ModePerm) + + // Process the files + for _, entry := range files { + fileName := filepath.Base(entry) + fixedFileName := getFixedName(fileName) + fixedFilePath := filepath.Join(dstPath, fixedFileName) + if err := copyFile(entry, fixedFilePath); err != nil { + return err + } + + archiveName := buildArchiveName(fileName, releaseName) + archivePath := filepath.Join(dstPath, archiveName) + + args := []string{ + "a", "-ma4", "-m0", "-ep", + "-v" + archiveSize, + "-rr3p", + "-hp" + archivePwd, + archivePath, + fixedFilePath, + } + if nfoFilePath != "" { + args = append(args, nfoFilePath) + } + + cmd := exec.Command(rarPath, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + + fmt.Printf("Creating archive: %s\n", archiveName) + err = cmd.Run() + if err != nil { + return fmt.Errorf("winrar failed: %w", err) + } + + os.Remove(fixedFilePath) + } + return nil +} + +func getFixedName(name string) string { + replacer := strings.NewReplacer( + "ä", "ae", + "ö", "oe", + "ü", "ue", + //" ", ".", + ) + return replacer.Replace(name) +} + +func buildArchiveName(fileName string, releaseName string) string { + re := regexp.MustCompile(`(?i)^(.*?)[\-\.\s]*(?:s?(\d+))?([ex])(\d+)([a-f]?)[\-\.\s]*(.*)$`) + m := re.FindStringSubmatch(fileName) + if len(m) == 0 { + return fmt.Sprintf("%s.rar", releaseName) + } + + season := m[2] + epd := m[3] + ep := m[4] + suff := m[5] + + if season != "" { + return fmt.Sprintf("%s.S%s%s%s.rar", releaseName, season, epd, ep) + } + return fmt.Sprintf("%s.%s%s%s.rar", releaseName, epd, ep, suff) +} diff --git a/task_pack_release/info.nfo.tmpl b/task_pack_release/info.nfo.tmpl new file mode 100644 index 0000000..02ed015 --- /dev/null +++ b/task_pack_release/info.nfo.tmpl @@ -0,0 +1,50 @@ + + /Maaa*p + >Oh$oci>>{8&*m[. + ""JWv!i>>xci>>{ki>>!1#k>. + '1@ti>>>>>>xci>>{ki>>>>>i[*0` + .]B~>>>>>>>>>xci>>{ki>>>>>>>>i*x` + .^hvi>>>>>iii!>uz?]_)k!ii>>>>>>>>[W!. + ':B?>>+t&%Whu1~l!iiii!!+)coW%*x_>i>!*}. + .:&wWZf+~nmo%pUur(}{}})jnUZ%MpC)<1YBbxo1' + !BL<_L%o|!i>>>>>>>>>>>>>>>>>>>>iiixMBQ--pBi + ;$8c_i>>>i!+fLqh&$*bppd*$8apOn[ii>>>>i>>($%b{!i>>>>>>>>>>>>>>>>i!i>ixn' + ';BL8L}iiiii~?{(tncYJCCCYcnf(1]+>!iiii[UWqCw` + `i$&@BBWBn|B$$$$%r&jjjjjjjOJW$$$$$YYB%BB@8#u, + :$Mz)}]?{B!:d$$d:uM+++++_-Yb'z$$#]:bX?[[)v8W,. + `)O~$+i!!!!?WBoWBk(M+++++++Ycc%@k@%u!!!!i~m(rQ"" + .:@!iZX>!!!!!!!!!!!/M+++++++Yc!!!!!!!!!!!>rpi+B; + .>%i>ih|>!!!!!!!!!!1$_++++++$}!!!!!!!!!!>?$i>i8+` + '}8>>>>#(>!!!!!!!!!+)@L[+[X8t]!!!!!!!!!>-8->>>Uj` + '}8>>>>ibc>!!!!!!!!>>}(|r||}+>!!!!!!!!>($>>>>>Jt^ + '~%i>>>>i/&]i!!!!!!!!!!iii!!!!!!!!!!i<*ui>>>>>@~^ + .!w1>>>>>>ifB(>!!!!!!!!!!!!!!!!!!!>]%U>>>>>>>[%!` + .^<$+>>>>>>>>~LWJ]i!!!!!!!!!!!!]zMm-i>>>>>>>~B+, + ,_%]>>>>>>>>>>i/B[>!!!!!!!!>8vi>>>>>>>>>>_@[,' + .""~Zb-ii>>>i}bor}~i!!!!!!!!>[tkh|ii>>>i~qd_;. + ^I~Z$@BB$kJfW%ciI!!!!!!!!ItM@v|zWBB@$&(I^ + -Bh|i>ibX!i_%B8t~{nCZZZ0v)+{$%@/!i>B_>i>>>>>no>>>-B<>>>>>>>-BM- + .chhhhkkkkkkkhaahkkkaabkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhhhhhhhm] + .B' d + :z@oUUUZt, d+ + qz!!!!!!!!j0 dWWfd+U8Y + +@imf!!!!!!!!!!{u ======================= d!!!XMld>ivp + ^W[!!!mf!!!!!!!!!!{u === Roemer Presents === d!!!!!!!p( +<&!!!!!LX!!!!!!!!!!/x ======================= d!!!!!ldt +d_!!!!!ldX!!!!!!!ljv h!!!!l8i +8!!!!!!!!~bW$MMMk| k!!!]$` +Ut!!!!!!!!!>B' b!!rd +'W!!!!!!!!!>B' {{ .Title1 }} blpj + 'Bf!!!!!lt&B' {{ .Title2 }} bmb. + .dM8Wa) 'B' d;{{ if .Infos }} +{{- range .Infos }} + 'B' {{ . }} d{{ end }} + 'B' d{{ end }}{{ if .Notes }} + 'B' === Notes === d + 'B' d +{{- range .Notes }} + 'B' {{ . }} d{{ end }} + 'B' d{{ end }} + ;#nffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffo1 diff --git a/task_pack_release/nfo.go b/task_pack_release/nfo.go new file mode 100644 index 0000000..7158980 --- /dev/null +++ b/task_pack_release/nfo.go @@ -0,0 +1,272 @@ +package task_pack_release + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "slices" + "strings" + "text/template" +) + +type NfoCreatorSettings struct { + Title string + Infos []*KeyValue + Notes string +} + +type KeyValue struct { + Key string + Value string +} + +type nfoTemplateData struct { + Title1 string + Title2 string + Infos []string + Notes []string +} + +func CreateNfo(dstPath string, settings *NfoCreatorSettings) (string, error) { + maxAllowedWidth := 65 + + // Prepare + nfoTemplateData := &nfoTemplateData{} + + // Handle the title + title := strings.ReplaceAll(settings.Title, " ", ".") + title = strings.ReplaceAll(title, "(", "") + title = strings.ReplaceAll(title, ")", "") + title = strings.ReplaceAll(title, ",", "") + title = strings.ReplaceAll(title, "&", "") + title = strings.ReplaceAll(title, "..", ".") + nfoTemplateData.Title1 = title + nfoTemplateData.Title2 = "" + if len(title) > maxAllowedWidth { + splitIndex := strings.LastIndexAny(title[:maxAllowedWidth], ".-") + nfoTemplateData.Title1 = title[:splitIndex] + nfoTemplateData.Title2 = title[splitIndex:] + } + nfoTemplateData.Title1 = fmt.Sprintf("%-*s", maxAllowedWidth, nfoTemplateData.Title1) + nfoTemplateData.Title2 = fmt.Sprintf("%-*s", maxAllowedWidth, nfoTemplateData.Title2) + + // Handle Infos + maxKey := slices.MaxFunc(settings.Infos, func(a, b *KeyValue) int { + if len(a.Key) < len(b.Key) { + return -1 + } else if len(a.Key) > len(b.Key) { + return 1 + } + return 0 + }) + maxKeyLen := len(maxKey.Key) + for _, info := range settings.Infos { + nfoTemplateData.Infos = append(nfoTemplateData.Infos, fmt.Sprintf("%-*s : %-*s", maxKeyLen, info.Key, maxAllowedWidth-maxKeyLen-3, info.Value)) + } + + // Handle Notes + noteLines := strings.SplitSeq(settings.Notes, "\n") + for note := range noteLines { + if len(note) > maxAllowedWidth { + splitIndex := strings.LastIndexAny(note[:maxAllowedWidth], " ") + nfoTemplateData.Notes = append(nfoTemplateData.Notes, fmt.Sprintf("%-*s", maxAllowedWidth, note[:splitIndex])) + nfoTemplateData.Notes = append(nfoTemplateData.Notes, fmt.Sprintf("%-*s", maxAllowedWidth, note[splitIndex+1:])) + } else { + nfoTemplateData.Notes = append(nfoTemplateData.Notes, fmt.Sprintf("%-*s", maxAllowedWidth, note)) + } + } + + // Parse the template file + t1, err := template.New("info.nfo.tmpl").ParseFiles("./task_pack_release/info.nfo.tmpl") + if err != nil { + return "", err + } + + // Execute the template to a memory buffer + var buf bytes.Buffer + if err := t1.Execute(&buf, nfoTemplateData); err != nil { + return "", err + } + + // Convert the buffer to string + content := buf.String() + + os.MkdirAll(dstPath, os.ModePerm) + nfoFilePath := filepath.Join(dstPath, fmt.Sprintf("%s.nfo", title)) + if err := os.WriteFile(nfoFilePath, []byte(content), os.ModePerm); err != nil { + return "", err + } + + return nfoFilePath, nil +} + +const ( + WebDL = "WEB-DL" + DvdRip = "DVDRip" + Bluray = "BluRay" + Dvd = "DVD" + YouTube = "YouTube" +) + +type TitleBuilder struct { + title string + season string + language string + quality string + resolution string + codec string + version string + dubbed bool + dualLanguage bool + enhanced bool + complete bool + extras bool + year string + episodes string +} + +// Constructor +func NewTitleBuilder(title string) *TitleBuilder { + return &TitleBuilder{title: title} +} + +func (t *TitleBuilder) Year(value int) *TitleBuilder { + t.year = fmt.Sprintf("(%d)", value) + return t +} + +func (t *TitleBuilder) Season(value int) *TitleBuilder { + t.season = fmt.Sprintf("S%02d", value) + return t +} + +func (t *TitleBuilder) EpisodeRange(first, last int) *TitleBuilder { + t.episodes = fmt.Sprintf("E%02d-E%02d", first, last) + return t +} + +func (t *TitleBuilder) German() *TitleBuilder { + t.language = "German" + return t +} + +func (t *TitleBuilder) Complete() *TitleBuilder { + t.complete = true + return t +} + +func (t *TitleBuilder) Dubbed() *TitleBuilder { + t.dubbed = true + return t +} + +func (t *TitleBuilder) Dual() *TitleBuilder { + t.dualLanguage = true + return t +} + +func (t *TitleBuilder) Enhanced() *TitleBuilder { + t.enhanced = true + return t +} + +func (t *TitleBuilder) Extras() *TitleBuilder { + t.extras = true + return t +} + +func (t *TitleBuilder) WebDL() *TitleBuilder { + t.quality = WebDL + return t +} + +func (t *TitleBuilder) DVDRip() *TitleBuilder { + t.quality = DvdRip + return t +} + +func (t *TitleBuilder) Bluray() *TitleBuilder { + t.quality = Bluray + return t +} + +func (t *TitleBuilder) R480() *TitleBuilder { + t.resolution = "480p" + return t +} + +func (t *TitleBuilder) R576() *TitleBuilder { + t.resolution = "576p" + return t +} + +func (t *TitleBuilder) R720p() *TitleBuilder { + t.resolution = "720p" + return t +} + +func (t *TitleBuilder) R1080p() *TitleBuilder { + t.resolution = "1080p" + return t +} + +func (t *TitleBuilder) X264() *TitleBuilder { + t.codec = "x264" + return t +} + +func (t *TitleBuilder) ReleaseVersion(version string) *TitleBuilder { + t.version = fmt.Sprintf("v%s", version) + return t +} + +func (t *TitleBuilder) Build() string { + var sb strings.Builder + + // Replace German umlauts + title := strings.NewReplacer( + "ö", "oe", + "ä", "ae", + "ü", "ue", + ).Replace(t.title) + + sb.WriteString(title) + addIfTrue(&sb, t.extras, "Extras") + addIfNotEmpty(&sb, t.year, false) + hasSeason := addIfNotEmpty(&sb, t.season, false) + addIfNotEmpty(&sb, t.episodes, hasSeason) + addIfTrue(&sb, t.complete, "Complete") + addIfNotEmpty(&sb, t.language, false) + addIfTrue(&sb, t.dubbed, "Dubbed") + addIfTrue(&sb, t.dualLanguage, "DL") + addIfNotEmpty(&sb, t.quality, false) + addIfNotEmpty(&sb, t.resolution, false) + addIfTrue(&sb, t.enhanced, "Enhanced") + addIfNotEmpty(&sb, t.codec, false) + addIfNotEmpty(&sb, t.version, false) + + sb.WriteString("-Roemer") + + return sb.String() +} + +func addIfNotEmpty(sb *strings.Builder, value string, skipDot bool) bool { + if strings.TrimSpace(value) != "" { + if !skipDot { + sb.WriteString(".") + } + sb.WriteString(value) + return true + } + return false +} + +func addIfTrue(sb *strings.Builder, value bool, text string) bool { + if value { + sb.WriteString(".") + sb.WriteString(text) + return true + } + return false +} diff --git a/task_pack_release/task.go b/task_pack_release/task.go new file mode 100644 index 0000000..c41e6d1 --- /dev/null +++ b/task_pack_release/task.go @@ -0,0 +1,13 @@ +package task_pack_release + +import "os" + +func PackRelease(srcPath string, dstPath string, releaseName string, archivePwd string, archiveSize string, nfoSettings *NfoCreatorSettings) error { + nfoPath, err := CreateNfo(dstPath, nfoSettings) + if err != nil { + return err + } + defer os.Remove(nfoPath) + + return compress(srcPath, dstPath, releaseName, archivePwd, archiveSize, nfoPath) +} diff --git a/task_pack_release/utils.go b/task_pack_release/utils.go new file mode 100644 index 0000000..a57d97a --- /dev/null +++ b/task_pack_release/utils.go @@ -0,0 +1,18 @@ +package task_pack_release + +import ( + "fmt" + "os" +) + +func copyFile(src, dst string) error { + data, err := os.ReadFile(src) + if err != nil { + return fmt.Errorf("read error: %w", err) + } + err = os.WriteFile(dst, data, 0644) + if err != nil { + return fmt.Errorf("write error: %w", err) + } + return nil +} diff --git a/tasks/black-border-analyze.go b/tasks/black-border-analyze.go new file mode 100644 index 0000000..0d333e0 --- /dev/null +++ b/tasks/black-border-analyze.go @@ -0,0 +1,185 @@ +package tasks + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "os/exec" + "path/filepath" + "regexp" + "strconv" + "strings" + "time" + + "github.com/roemer/goext" +) + +type BlackBorderAnalyzeTask struct { + logFilePath string + cropDetectOutputRegex *regexp.Regexp +} + +func NewBlackBorderAnalyzeTask(logFilePath string) *BlackBorderAnalyzeTask { + return &BlackBorderAnalyzeTask{ + logFilePath: logFilePath, + cropDetectOutputRegex: regexp.MustCompile(`.*Parsed_cropdetect_0.* x1:([0-9]+) x2:([0-9]+) y1:([0-9]+) y2:([0-9]+) w:([0-9]+) h:([0-9]+) x:([0-9]+) y:([0-9]+) pts:([0-9]+) t:([0-9\.]+) limit:([0-9\.]+) crop=([0-9\:]+)`), + } +} + +func (t *BlackBorderAnalyzeTask) Run(folderPath string) error { + files, err := os.ReadDir(folderPath) + if err != nil { + return fmt.Errorf("failed to read directory: %w", err) + } + for _, file := range files { + // Skip directories + if file.IsDir() { + continue + } + // Skip reencoded files + if strings.HasSuffix(file.Name(), "_2.mkv") { + continue + } + t.output(fmt.Sprintf("=== %s", file.Name())) + if err := t.processFile(filepath.Join(folderPath, file.Name())); err != nil { + return fmt.Errorf("failed to process file %s: %w", file.Name(), err) + } + } + return nil +} + +func (t *BlackBorderAnalyzeTask) processFile(filePath string) error { + // Get the resolution of the video + resOutput, _, err := goext.CmdRunners.Default.RunGetOutput("ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries", "stream=width,height", "-of", "json", filePath) + if err != nil { + return fmt.Errorf("failed to run ffprobe: %w", err) + } + decoder := json.NewDecoder(strings.NewReader(resOutput)) + var result struct { + Streams []struct { + Width int `json:"width"` + Height int `json:"height"` + } `json:"streams"` + } + if err := decoder.Decode(&result); err != nil { + return fmt.Errorf("failed to decode ffprobe output: %w", err) + } + videoWidth := result.Streams[0].Width + videoHeight := result.Streams[0].Height + + // Execute a command and process output in real time + cmd := exec.Command("ffmpeg", "-v", "debug", "-i", filePath, "-vf", "cropdetect", "-f", "null", "-") + + // Create a single pipe that combines both stdout and stderr + combinedOutput, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("failed to create stdout pipe: %w", err) + } + + // Redirect stderr to stdout so both streams are handled together + cmd.Stderr = cmd.Stdout + + // Start the command + if err := cmd.Start(); err != nil { + return fmt.Errorf("failed to start command: %w", err) + } + + // Process combined output in real time with a single goroutine + go func() { + lastValue := &blackBorderAnalyzeData{} + scanner := bufio.NewScanner(combinedOutput) + for scanner.Scan() { + line := scanner.Text() + // Process each line of combined output here + value := t.processOutputLine(line) + if value != nil { + if value.x1 != lastValue.x1 || value.x2 != lastValue.x2 || value.y1 != lastValue.y1 || value.y2 != lastValue.y2 || value.w != lastValue.w || value.h != lastValue.h || value.x != lastValue.x || value.y != lastValue.y { + // output(value.String()) + t.output(fmt.Sprintf("left=%d, right=%d, top=%d, bottom=%d, time:%s", + value.x1, videoWidth-value.x2, value.y1, videoHeight-value.y2, value.timeStamp)) + } + lastValue = value + } + } + if err := scanner.Err(); err != nil { + fmt.Fprintf(os.Stderr, "Error reading combined output: %v\n", err) + } + }() + + // Wait for the command to complete + return cmd.Wait() +} + +func (t *BlackBorderAnalyzeTask) processOutputLine(line string) *blackBorderAnalyzeData { + match := t.cropDetectOutputRegex.FindStringSubmatch(line) + if match != nil { + //fmt.Println(line) + // Extracted values can be processed further + x1 := match[1] + x2 := match[2] + y1 := match[3] + y2 := match[4] + w := match[5] + h := match[6] + x := match[7] + y := match[8] + //pts := match[9] + t := match[10] + //limit := match[11] + //crop := match[12] + + x1v, _ := strconv.Atoi(x1) + x2v, _ := strconv.Atoi(x2) + y1v, _ := strconv.Atoi(y1) + y2v, _ := strconv.Atoi(y2) + wv, _ := strconv.Atoi(w) + hv, _ := strconv.Atoi(h) + xv, _ := strconv.Atoi(x) + yv, _ := strconv.Atoi(y) + timeStamp, _ := strconv.ParseFloat(t, 64) + return &blackBorderAnalyzeData{ + x1: x1v, + x2: x2v, + y1: y1v, + y2: y2v, + w: wv, + h: hv, + x: xv, + y: yv, + timeStamp: time.Duration(timeStamp * float64(time.Second)), + } + } + return nil +} + +func (t *BlackBorderAnalyzeTask) output(value string) { + fmt.Println(value) + // Append to file + f, err := os.OpenFile(t.logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "Error opening file for writing: %v\n", err) + return + } + defer f.Close() + + if _, err := f.WriteString(value + "\n"); err != nil { + fmt.Fprintf(os.Stderr, "Error writing to file: %v\n", err) + } +} + +type blackBorderAnalyzeData struct { + x1 int + x2 int + y1 int + y2 int + w int + h int + x int + y int + timeStamp time.Duration +} + +func (c blackBorderAnalyzeData) String() string { + return fmt.Sprintf("x1: %d, x2: %d, y1: %d, y2: %d, w: %d, h: %d, x: %d, y: %d, timeStamp: %s", c.x1, c.x2, c.y1, c.y2, c.w, c.h, c.x, c.y, c.timeStamp) +} diff --git a/tasks/epic-link.go b/tasks/epic-link.go new file mode 100644 index 0000000..a7eafbf --- /dev/null +++ b/tasks/epic-link.go @@ -0,0 +1,89 @@ +package tasks + +import ( + "encoding/json" + "fmt" + "net/http" + "strings" + "time" +) + +type EpicLinkTask struct{} + +func (t *EpicLinkTask) Run() error { + jsonContent, err := http.Get("https://api.egdata.app/free-games?country=US") + if err != nil { + return fmt.Errorf("failed fetching link") + } + defer jsonContent.Body.Close() + + var parsedJson []struct { + ID string `json:"id"` + Namespace string `json:"namespace"` + Title string `json:"title"` + Tags []struct { + ID string `json:"id"` + Name string `json:"name"` + } `json:"tags"` + Giveaway struct { + ID string `json:"id"` + Namespace string `json:"namespace"` + StartDate time.Time `json:"startDate"` + EndDate time.Time `json:"endDate"` + Title string `json:"title"` + } `json:"giveaway"` + } + decoder := json.NewDecoder(jsonContent.Body) + if err := decoder.Decode(&parsedJson); err != nil { + return fmt.Errorf("failed decoding JSON: %w", err) + } + + offers := []*EpicOffer{} + for _, item := range parsedJson { + if item.Giveaway.StartDate.Before(time.Now()) { + offer := &EpicOffer{ + Title: item.Title, + Namespace: item.Namespace, + OfferId: item.ID, + } + for _, tag := range item.Tags { + switch tag.Name { + case "Windows": + offer.System = "PC" + offers = append(offers, offer) + case "iOS": + offer.System = "iOS" + offers = append(offers, offer) + case "Android": + offer.System = "Android" + offers = append(offers, offer) + } + } + } + } + + allOffers := "" + for _, offer := range offers { + fmt.Printf("%s (%s):\n%s\n\n", offer.Title, offer.System, t.toOfferUrl(offer.ToOffer())) + allOffers += offer.ToOffer() + "&" + } + allOffers = strings.TrimSuffix(allOffers, "&") + fmt.Printf("All Offers:\n%s\n", t.toOfferUrl(allOffers)) + + return nil +} + +func (t *EpicLinkTask) toOfferUrl(offerString string) string { + return fmt.Sprintf("https://store.epicgames.com/purchase?%s#/purchase/payment-methods", offerString) +} + +type EpicOffer struct { + Title string + System string + Namespace string + OfferId string +} + +func (o *EpicOffer) ToOffer() string { + return fmt.Sprintf("offers=1-%s-%s", o.Namespace, o.OfferId) +} diff --git a/tasks/mega-account.go b/tasks/mega-account.go new file mode 100644 index 0000000..2740887 --- /dev/null +++ b/tasks/mega-account.go @@ -0,0 +1,163 @@ +package tasks + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "regexp" + "time" +) + +type MegaAccountTask struct{} + +// jim +// fnkezq4o3a@zudpck.com +// 7xIz9GqR1CRvRpLv + +func (t *MegaAccountTask) Run() error { + firstName, lastName, err := t.getRandomName() + if err != nil { + return err + } + fmt.Println("First Name:", firstName) + fmt.Println("Last Name:", lastName) + + pwd, err := t.getRandomPassword() + if err != nil { + return err + } + fmt.Println("Password:", pwd) + + tempMail, err := t.createTempMail() + if err != nil { + return err + } + fmt.Println("Temp Mail:", tempMail) + + verificationLink, err := t.getVerificationLink(tempMail) + if err != nil { + return err + } + fmt.Println("Verification Link:", verificationLink) + return nil +} + +func (t *MegaAccountTask) getRandomName() (string, string, error) { + apiUrl := "https://randomuser.me/api/" + resp, err := http.Get(apiUrl) + if err != nil { + return "", "", err + } + defer resp.Body.Close() + + var jsonData struct { + Results []struct { + Name struct { + Title string `json:"title"` + First string `json:"first"` + Last string `json:"last"` + } `json:"name"` + } `json:"results"` + } + + if err := json.NewDecoder(resp.Body).Decode(&jsonData); err != nil { + return "", "", err + } + + return jsonData.Results[0].Name.First, jsonData.Results[0].Name.Last, nil +} + +func (t *MegaAccountTask) getRandomPassword() (string, error) { + apiUrl := "https://passwordwolf.com/api/?special=off&length=16&repeat=1" + resp, err := http.Get(apiUrl) + if err != nil { + return "", err + } + defer resp.Body.Close() + + var jsonData []struct { + Password string `json:"password"` + } + + if err := json.NewDecoder(resp.Body).Decode(&jsonData); err != nil { + return "", err + } + + return jsonData[0].Password, nil +} + +func (t *MegaAccountTask) createTempMail() (string, error) { + url := "https://api.internal.temp-mail.io/api/v3/email/new" + data := map[string]int{ + "min_name_length": 10, + "max_name_length": 10, + } + jsonData, err := json.Marshal(data) + if err != nil { + return "", err + } + + resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData)) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var rawEmail map[string]interface{} + if err := json.Unmarshal(body, &rawEmail); err != nil { + return "", err + } + + return rawEmail["email"].(string), nil +} + +func (t *MegaAccountTask) getVerificationLink(email string) (string, error) { + url := fmt.Sprintf("https://api.internal.temp-mail.io/api/v3/email/%s/messages", email) + + fmt.Println("Waiting for verification link...") + for { + resp, err := http.Get(url) + if err != nil { + return "", err + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", err + } + + var emails []struct { + Id string `json:"id"` + From string `json:"from"` + Subject string `json:"subject"` + BodyText string `json:"body_text"` + BodyHTML string `json:"body_html"` + } + if err := json.Unmarshal(body, &emails); err != nil { + return "", err + } + + if len(emails) == 0 { + // Retry + time.Sleep(10 * time.Second) + continue + } + + emailText := emails[0].BodyText + reg := regexp.MustCompile(`(https:\/\/mega.nz\/#[a-zA-Z0-9\-_]+)`) + matches := reg.FindStringSubmatch(emailText) + if len(matches) < 2 { + return "", fmt.Errorf("verification link not found in email") + } + + return matches[1], nil + } +}