Initial commit
This commit is contained in:
108
task_pack_release/compress.go
Normal file
108
task_pack_release/compress.go
Normal file
@@ -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)
|
||||
}
|
||||
50
task_pack_release/info.nfo.tmpl
Normal file
50
task_pack_release/info.nfo.tmpl
Normal file
@@ -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%Z
|
||||
^$i>>>($%b{!i>>>>>>>>>>>>>>>>i!<u8B*{>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<C8r^
|
||||
<M$B~>>>>>>no>><B8@8df_~~+}cW@8&@[>>-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
|
||||
272
task_pack_release/nfo.go
Normal file
272
task_pack_release/nfo.go
Normal file
@@ -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
|
||||
}
|
||||
13
task_pack_release/task.go
Normal file
13
task_pack_release/task.go
Normal file
@@ -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)
|
||||
}
|
||||
18
task_pack_release/utils.go
Normal file
18
task_pack_release/utils.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user