// // rhimportd // // The Radio Helsinki Rivendell Import Daemon // // // Copyright (C) 2015 Christian Pointner // // This file is part of rhimportd. // // rhimportd is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // rhimportd is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with rhimportd. If not, see . // package rhimport import ( "bytes" "fmt" "io" "mime/multipart" "net/http" "os" "path" ) var ( bool2str = map[bool]string{false: "0", true: "1"} ) type ImportContext struct { *Config *RdDb UserName string Password string Trusted bool ShowId int GroupName string Cart int Cut int Channels int NormalizationLevel int AutotrimLevel int UseMetaData bool SourceUri string SourceFile string DeleteSourceFile bool DeleteSourceDir bool ProgressCallBack func(step int, step_name string, progress float64, userdata interface{}) ProgressCallBackData interface{} } func NewImportContext(conf *Config, rddb *RdDb, user string, group string) *ImportContext { ctx := new(ImportContext) ctx.Config = conf ctx.RdDb = rddb ctx.UserName = user ctx.Password = "" ctx.Trusted = false ctx.ShowId = 0 ctx.GroupName = group ctx.Cart = 0 ctx.Cut = 0 ctx.Channels = 2 ctx.NormalizationLevel = -1200 ctx.AutotrimLevel = 0 ctx.UseMetaData = false ctx.SourceFile = "" ctx.DeleteSourceFile = false ctx.DeleteSourceDir = false ctx.ProgressCallBack = nil return ctx } func (ctx *ImportContext) getPassword(cached bool) (err error) { req := getPasswordRequest{} req.username = ctx.UserName req.cached = cached req.response = make(chan getPasswordResult) ctx.RdDb.getPasswordChan <- req res := <-req.response if res.err != nil { err = res.err return } ctx.Password = res.password return } func (ctx *ImportContext) getShowInfo() (err error) { req := getShowInfoRequest{} req.showid = ctx.ShowId req.response = make(chan getShowInfoResult) ctx.RdDb.getShowInfoChan <- req res := <-req.response if res.err != nil { err = res.err return } rhdl.Printf("Title of show %d is '%s'", ctx.ShowId, res.title) return } func send_post_request(url string, b *bytes.Buffer, contenttype string) (err error) { var req *http.Request if req, err = http.NewRequest("POST", url, b); err != nil { return } if contenttype != "" { req.Header.Set("Content-Type", contenttype) } client := &http.Client{} var res *http.Response if res, err = client.Do(req); err != nil { return } defer res.Body.Close() if res.StatusCode != http.StatusOK { // TODO: better error output err = fmt.Errorf("bad status: %s", res.Status) } return } func add_cart(ctx *ImportContext) (err error) { var b bytes.Buffer w := multipart.NewWriter(&b) if err = w.WriteField("COMMAND", "12"); err != nil { return } if err = w.WriteField("LOGIN_NAME", ctx.UserName); err != nil { return } if err = w.WriteField("PASSWORD", ctx.Password); err != nil { return } if err = w.WriteField("GRPOUP_NAME", ctx.GroupName); err != nil { return } if err = w.WriteField("TYPE", "audio"); err != nil { return } if ctx.Cart != 0 { if err = w.WriteField("CART_NUMBER", fmt.Sprintf("%d", ctx.Cart)); err != nil { return } } w.Close() return send_post_request(ctx.Config.RDXportEndpoint, &b, w.FormDataContentType()) } func add_cut(ctx *ImportContext) (err error) { var b bytes.Buffer w := multipart.NewWriter(&b) if err = w.WriteField("COMMAND", "10"); err != nil { return } if err = w.WriteField("LOGIN_NAME", ctx.UserName); err != nil { return } if err = w.WriteField("PASSWORD", ctx.Password); err != nil { return } if err = w.WriteField("CART_NUMBER", fmt.Sprintf("%d", ctx.Cart)); err != nil { return } w.Close() return send_post_request(ctx.Config.RDXportEndpoint, &b, w.FormDataContentType()) } func remove_cart(ctx *ImportContext) (err error) { var b bytes.Buffer w := multipart.NewWriter(&b) if err = w.WriteField("COMMAND", "13"); err != nil { return } if err = w.WriteField("LOGIN_NAME", ctx.UserName); err != nil { return } if err = w.WriteField("PASSWORD", ctx.Password); err != nil { return } if err = w.WriteField("CART_NUMBER", fmt.Sprintf("%d", ctx.Cart)); err != nil { return } w.Close() return send_post_request(ctx.Config.RDXportEndpoint, &b, w.FormDataContentType()) } func import_audio(ctx *ImportContext) (err error) { var b bytes.Buffer w := multipart.NewWriter(&b) if err = w.WriteField("COMMAND", "2"); err != nil { return } if err = w.WriteField("LOGIN_NAME", ctx.UserName); err != nil { return } if err = w.WriteField("PASSWORD", ctx.Password); err != nil { return } if err = w.WriteField("CART_NUMBER", fmt.Sprintf("%d", ctx.Cart)); err != nil { return } if err = w.WriteField("CUT_NUMBER", fmt.Sprintf("%d", ctx.Cut)); err != nil { return } if err = w.WriteField("CHANNELS", fmt.Sprintf("%d", ctx.Channels)); err != nil { return } if err = w.WriteField("NORMALIZATION_LEVEL", fmt.Sprintf("%d", ctx.NormalizationLevel)); err != nil { return } if err = w.WriteField("AUTOTRIM_LEVEL", fmt.Sprintf("%d", ctx.AutotrimLevel)); err != nil { return } if err = w.WriteField("USE_METADATA", bool2str[ctx.UseMetaData]); err != nil { return } var f *os.File var fw io.Writer if f, err = os.Open(ctx.SourceFile); err != nil { return } if fw, err = w.CreateFormFile("FILENAME", path.Base(ctx.SourceFile)); err != nil { return } if _, err = io.Copy(fw, f); err != nil { return } f.Close() w.Close() return send_post_request(ctx.Config.RDXportEndpoint, &b, w.FormDataContentType()) } func cleanup_files(ctx *ImportContext) { if ctx.DeleteSourceFile { rhdl.Printf("importer: removing file: %s", ctx.SourceFile) if err := os.Remove(ctx.SourceFile); err != nil { rhl.Printf("importer: error removing source file: %s", err) return } if ctx.DeleteSourceDir { dir := path.Dir(ctx.SourceFile) rhdl.Printf("importer: also removing directory: %s", dir) if err := os.Remove(dir); err != nil { rhl.Printf("importer: error removing source directory: %s", err) } } } return } func ImportFile(ctx *ImportContext) (err error) { rhl.Println("ImportFile called for", ctx.SourceFile) defer cleanup_files(ctx) if ctx.ProgressCallBack != nil { ctx.ProgressCallBack(2, "importing", 0.0, ctx.ProgressCallBackData) } if ctx.Trusted { if err = ctx.getPassword(true); err != nil { return } } if err = import_audio(ctx); err != nil { return } if ctx.ProgressCallBack != nil { ctx.ProgressCallBack(2, "importing", 1.0, ctx.ProgressCallBackData) } rhl.Println("ImportFile succesfully imported", ctx.SourceFile) return }