Skip to content

Commit

Permalink
v1.0.0 (#2)
Browse files Browse the repository at this point in the history
* Initial version
  • Loading branch information
l3uddz authored Feb 5, 2020
1 parent 60ca877 commit c5d292c
Show file tree
Hide file tree
Showing 28 changed files with 2,559 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# misc
/.idea/
/.vscode/

# configuration
config.json
*.db

# vendor files
/vendor/

# dist folder
/dist/

# Web package
web/rice-box.go
web/trackarr-ui/package-lock.json
90 changes: 90 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
.DEFAULT_GOAL := build
CMD := wantarr
GOARCH := $(shell go env GOARCH)
GOOS := $(shell go env GOOS)
TARGET := ${GOOS}_${GOARCH}
DIST_PATH := dist
BUILD_PATH := ${DIST_PATH}/${CMD}_${TARGET}
DESTDIR := /usr/local/bin
GO_FILES := $(shell find . -path ./vendor -prune -or -type f -name '*.go' -print)
GO_PACKAGES := $(shell go list -mod vendor ./...)
GIT_COMMIT := $(shell git rev-parse --short HEAD)
# GIT_BRANCH := $(shell git symbolic-ref --short HEAD)
TIMESTAMP := $(shell date +%s)
VERSION ?= 0.0.0-dev

# Deps
.PHONY: check_golangci
check_golangci:
@command -v golangci-lint >/dev/null || (echo "golangci-lint is required."; exit 1)
.PHONY: check_goreleaser
check_goreleaser:
@command -v goreleaser >/dev/null || (echo "goreleaser is required."; exit 1)

.PHONY: all ## Run tests, linting and build
all: test lint build

.PHONY: test-all ## Run tests and linting
test-all: test lint

.PHONY: test
test: ## Run tests
@echo "*** go test ***"
go test -cover -mod vendor -v -race ${GO_PACKAGES}

.PHONY: lint
lint: check_golangci ## Run linting
@echo "*** golangci-lint ***"
golangci-lint run

.PHONY: vendor
vendor: ## Vendor files and tidy go.mod
go mod vendor
go mod tidy

.PHONY: vendor_update
vendor_update: ## Update vendor dependencies
go get -u ./...
${MAKE} vendor

.PHONY: build
build: fetch ${BUILD_PATH}/${CMD} ## Build application

# Binary
${BUILD_PATH}/${CMD}: ${GO_FILES} go.sum
@echo "Building for ${TARGET}..." && \
mkdir -p ${BUILD_PATH} && \
CGO_ENABLED=1 go build \
-mod vendor \
-trimpath \
-ldflags "-s -w -X github.com/l3uddz/wantarr/build.Version=${VERSION} -X github.com/l3uddz/wantarr/build.GitCommit=${GIT_COMMIT} -X github.com/l3uddz/wantarr/build.Timestamp=${TIMESTAMP}" \
-o ${BUILD_PATH}/${CMD} \
.

.PHONY: install
install: build ## Install binary
install -m 0755 ${BUILD_PATH}/${CMD} ${DESTDIR}/${CMD}

.PHONY: clean
clean: ## Cleanup
rm -rf ${DIST_PATH}

.PHONY: fetch
fetch: ## Fetch vendor files
go mod vendor

.PHONY: release
release: check_goreleaser fetch ## Generate a release, but don't publish
goreleaser --skip-validate --skip-publish --rm-dist

.PHONY: publish
publish: check_goreleaser fetch ## Generate a release, and publish
goreleaser --rm-dist

.PHONY: snapshot
snapshot: check_goreleaser fetch ## Generate a snapshot release
goreleaser --snapshot --skip-validate --skip-publish --rm-dist

.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
52 changes: 52 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
version: 1.0.{build}

image:
- Ubuntu1804
- macOS

platform: x64

branches:
only:
- master
- develop

deploy:
- provider: GitHub
auth_token:
secure: japCKJyRSrHvPJV0hqZZGcRM9ZSR9GsTVh8SCCwbqiyuKTyB3OCcRMc6ICztczfV
artifact: wantarr
force_update: true
on:
branch: master
APPVEYOR_REPO_TAG: true

cache:
- vendor -> go.mod, appveyor.yml

artifacts:
- path: dist/**/*.tar.tgz
name: wantarr

environment:
GO111MODULE: on

install:
- go version
- go env

before_build:
- |-
if [ ${APPVEYOR_REPO_TAG} = "true" ]; then
export VERSION=${APPVEYOR_REPO_TAG_NAME}
fi
build_script:
- make build

after_build:
- |-
export build=$(find dist/* -type d | sed 's!.*/!!')
cd dist/$build
tar -czf $build.tar.tgz wantarr
cd ../..
8 changes: 8 additions & 0 deletions build/vars.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package build

var (
// Build Vars
Version string
Timestamp string
GitCommit string
)
190 changes: 190 additions & 0 deletions cmd/cutoff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
package cmd

import (
"github.com/l3uddz/wantarr/database"
pvrObj "github.com/l3uddz/wantarr/pvr"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/tommysolsen/capitalise"
"time"
)

var cutoffCmd = &cobra.Command{
Use: "cutoff [PVR]",
Short: "Search for cutoff unmet media files",
Long: `This command can be used to search for cutoff unmet media files from the respective arr wanted list.`,

Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
// validate inputs
if err := parseValidateInputs(args); err != nil {
log.WithError(err).Fatal("Failed validating inputs")
}

// init pvr object
if err := pvr.Init(); err != nil {
log.WithError(err).Fatalf("Failed initializing pvr object for: %s", pvrName)
}

// load database
if err := database.Init(flagDatabaseFile); err != nil {
log.WithError(err).Fatal("Failed opening database file")
}
defer database.Close()

// retrieve cutoff records from pvr and stash in database
existingItemsCount := database.GetItemsCount(lowerPvrName, "cutoff")
if flagRefreshCache || existingItemsCount < 1 {
log.Infof("Retrieving cutoff unmet media from %s: %q", capitalise.First(pvrConfig.Type), pvrName)

cutoffRecords, err := pvr.GetWantedCutoff()
if err != nil {
log.WithError(err).Fatal("Failed retrieving wanted cutoff unmet pvr items...")
}

// stash cutoff media in database
log.Debug("Stashing media items in database...")

if err := database.SetMediaItems(lowerPvrName, "cutoff", cutoffRecords); err != nil {
log.WithError(err).Fatal("Failed stashing media items in database")
}

log.Info("Stashed media items")

// remove media no longer cutoff unmet
if existingItemsCount >= 1 {
log.Debug("Removing media items from database that are no longer cutoff unmet...")

removedItems, err := database.DeleteMissingItems(lowerPvrName, "cutoff", cutoffRecords)
if err != nil {
log.WithError(err).Fatal("Failed removing media items from database that are no longer cutoff unmet...")
}

log.WithField("removed_items", removedItems).
Info("Removed media items from database that are no longer cutoff unmet")
}
}

// start queue monitor
if maxQueueSize > 0 {
go func() {
log.Info("Started queue monitor")
for {
// retrieve queue size
qs, err := pvr.GetQueueSize()
if err != nil {
log.WithError(err).Error("Failed retrieving queue size, aborting...")
continueRunning.Store(false)
break
}

// check queue size
if qs >= maxQueueSize {
log.Warnf("Queue size has been reached, aborting....")
continueRunning.Store(false)
break
}

// sleep before check
time.Sleep(10 * time.Second)
}
log.Info("Finished queue monitor")
}()
}

// get media items from database
mediaItems, err := database.GetMediaItems(lowerPvrName, "cutoff", false)
if err != nil {
log.WithError(err).Fatal("Failed retrieving media items from database...")
}
log.WithField("media_items", len(mediaItems)).Debug("Retrieved media items from database")

// start searching
var searchItems []pvrObj.MediaItem
searchedItemsCount := 0

for _, item := range mediaItems {
// abort if required (queue monitor will set this)
if !continueRunning.Load() {
break
}

// dont search this item if we already searched it within N days
if item.LastSearchDateUtc != nil && !item.LastSearchDateUtc.IsZero() {
retryAfterDate := item.LastSearchDateUtc.Add((24 * time.Hour) * pvrConfig.RetryDaysAge.Cutoff)
if time.Now().UTC().Before(retryAfterDate) {
log.WithField("retry_min_date", retryAfterDate).
Tracef("Skipping media item %v until allowed retry date", item.Id)
continue
}
}

// add item to batch
searchItems = append(searchItems, pvrObj.MediaItem{
ItemId: item.Id,
AirDateUtc: item.AirDateUtc,
})

// not enough items batched yet
batchedItemsCount := len(searchItems)
if batchedItemsCount < searchBatchSize {
continue
}

// do search
log.WithFields(logrus.Fields{
"search_items": batchedItemsCount,
}).Info("Searching...")

searchedItemsCount += batchedItemsCount

if _, err := searchForItems(searchItems, "cutoff"); err != nil {
log.WithError(err).Error("Failed searching for items...")
} else {
log.WithFields(logrus.Fields{
"searched_items": searchedItemsCount,
}).Info("Search complete")
}

// reset batch
searchItems = []pvrObj.MediaItem{}

// max search items reached?
if maxSearchItems > 0 && searchedItemsCount >= maxSearchItems {
log.WithField("searched_items", searchedItemsCount).
Info("Max search items reached, aborting...")
break
}

// sleep before next batch
time.Sleep(5 * time.Second)
}

// search for any leftover items from batching
if continueRunning.Load() && len(searchItems) > 0 {
// search items
log.WithFields(logrus.Fields{
"search_items": len(searchItems),
}).Info("Searching...")

searchedItemsCount += len(searchItems)

if _, err := searchForItems(searchItems, "cutoff"); err != nil {
log.WithError(err).Error("Failed searching for items...")
} else {
log.WithFields(logrus.Fields{
"searched_items": searchedItemsCount,
}).Info("Search complete")
}
}
},
}

func init() {
rootCmd.AddCommand(cutoffCmd)

cutoffCmd.Flags().IntVarP(&maxQueueSize, "queue-size", "q", 0, "Exit when queue size reached.")
cutoffCmd.Flags().IntVarP(&maxSearchItems, "max-search", "m", 0, "Exit when this many items have been searched.")
cutoffCmd.Flags().IntVarP(&searchBatchSize, "search-size", "s", 10, "How many items to search at once.")
cutoffCmd.Flags().BoolVarP(&flagRefreshCache, "refresh-cache", "r", false, "Refresh the locally stored cache.")
}
Loading

0 comments on commit c5d292c

Please sign in to comment.