Skip to content

Commit

Permalink
init release
Browse files Browse the repository at this point in the history
  • Loading branch information
sjurtf committed Mar 14, 2021
1 parent 1635977 commit 294f922
Show file tree
Hide file tree
Showing 11 changed files with 549 additions and 0 deletions.
25 changes: 25 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FROM golang:1.16.2 as builder

ENV GO111MODULE=on \
CGO_ENABLED=0 \
GOOS=linux \
GOARCH=amd64

WORKDIR /app

COPY go.mod .
#COPY go.sum .
RUN go mod download

COPY . /app
RUN go build -o binary .

FROM alpine:latest

RUN addgroup -S app && adduser -S app -G app

WORKDIR /app
COPY --from=builder /app/binary .

USER app
ENTRYPOINT ["./binary"]
2 changes: 2 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#/bin/sh
docker build . -t xmltv-exporter
112 changes: 112 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package cmd

import (
"fmt"
"log"
"net/http"
"path"
"strings"
"time"
"xmltv-exporter/xmltv"
)

func ServeEpg() {

http.HandleFunc("/channels-norway.xml", ChannelListHandler)
http.HandleFunc("/", ChannelHandler)

if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}

func ChannelListHandler(w http.ResponseWriter, r *http.Request) {
if !isValid(w, r) {
return
}

bytes, err := xmltv.GetChannelList()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

_, _ = w.Write(bytes)
}

func ChannelHandler(w http.ResponseWriter, r *http.Request) {
if !isValid(w, r) {
return
}

channelId, err := channelId(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

date, err := date(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}

bytes, err := xmltv.GetSchedule(channelId, date)
if err != nil {
http.Error(w, err.Error(), http.StatusNotFound)
return
}

_, _ = w.Write(bytes)
}

/**
Finds channelId from Path
Example input: zebrahd.tv2.no_2021-03-16.xml.gz
*/
func channelId(r *http.Request) (string, error) {
filename := path.Base(r.URL.Path)
parts := strings.Split(filename, "_")

if len(parts) == 0 {
return "", fmt.Errorf("channel name could not be found from input '%s'", filename)
}
return parts[0], nil
}

/**
Finds time.Time from Path
Example input: zebrahd.tv2.no_2021-03-16.xml.gz
*/
func date(r *http.Request) (time.Time, error) {
filename := path.Base(r.URL.Path)
parts := strings.Split(filename, "_")

if len(parts) <= 1 {
return time.Time{}, fmt.Errorf("date could not be found from input '%s'", filename)
}

parts2 := strings.Split(parts[1], ".")

date, err := time.Parse("2006-01-02", parts2[0])
if err != nil {
return time.Time{}, fmt.Errorf("date could not be parsed: '%s'", err)

}

return date, nil
}

func isValid(w http.ResponseWriter, r *http.Request) bool {
if r.Method != http.MethodGet {
http.Error(w, "Method is not supported", http.StatusMethodNotAllowed)
return false
}

if len(r.URL.Path) <= 1 {
http.Error(w, "Not found", http.StatusNotFound)
return false
}

return true
}
28 changes: 28 additions & 0 deletions cmd/transform.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cmd

import (
"log"
"time"
"xmltv-exporter/tv2"
"xmltv-exporter/xmltv"
)

func MapEgp() {
today := time.Now()
futureOneWeek := time.Now().Add(time.Hour * 24 * 3)

var t = today
for t.Before(futureOneWeek) {
channels := tv2.FetchEpg(today)
xmltv.UpdateAvailableChannels(channels)

// TODO make this more efficient
for _, channel := range channels {
xmltv.BuildCache(t, channel)
}

t = t.Add(time.Hour * 24)
log.Printf("date: %s", t)
}
log.Println("Epg cache refreshed")
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module xmltv-exporter

go 1.16
8 changes: 8 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package main

import "xmltv-exporter/cmd"

func main() {
cmd.MapEgp()
cmd.ServeEpg()
}
56 changes: 56 additions & 0 deletions tv2/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package tv2

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
)

//
// https://rest.tv2.no/epg-dw-rest/epg/program/2021/03/15/
//
const (
rootUrl = "https://rest.tv2.no/epg-dw-rest/epg/program/"
userAgent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:86.0) Gecko/20100101 Firefox/86.0"
)

func FetchEpg(date time.Time) []Channel {
day := date.Day()
month := date.Month()
year := date.Year()

datePath := fmt.Sprintf("%d/%d/%d", year, int(month), day)

client := &http.Client{}
req, err := http.NewRequest(http.MethodGet, rootUrl+datePath, nil)
if err != nil {
log.Fatalln(err)
}

req.Header.Set("User-Agent", userAgent)

resp, err := client.Do(req)
if err != nil {
log.Fatalf("unable to get data: %s", err)
}
if resp.StatusCode != 200 {
log.Printf("got unhappy statuscode: %d", resp.StatusCode)
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}

r := &Response{}
err = json.Unmarshal(body, r)
if err != nil {
log.Fatalf("unable to decode data: %s", err)
}

return r.Channels
}
44 changes: 44 additions & 0 deletions tv2/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tv2

import (
"time"
)

type Response struct {
Date string `json:"date"`
Channels []Channel `json:"channel"`
}

type Channel struct {
Id int `json:"id"`
Name string `json:"name"`
ShortName string `json:"shortName"`
Category string `json:"category"`
Score int `json:"score"`
Tv2Id int `json:"tv2id"`
Programs []Program `json:"program"`
}

type Program struct {
Id int `json:"id"`
SeriesId string `json:"srsid"`
ProgramId string `json:"programId"`
House string `json:"house"`
Title string `json:"title"`
Start time.Time `json:"start"`
Stop time.Time `json:"stop"`
Episode int `json:"epnr"`
EpisodeTotal int `json:"eptot"`
Season int `json:"season"`
SeriesSynopsis string `json:"srsyn"`
EpisodeSynopsis string `json:"epsyn"`

Nationality string `json:"natio"`
Genre string `json:"genre"`
ProductionYear int `json:"pyear"`

IsReplay bool `json:"isrepl"`
IsLive bool `json:"islive"`
IsMovie bool `json:"ismov"`
IsSyn bool `json:"issyn"`
}
86 changes: 86 additions & 0 deletions xmltv/channelmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package xmltv

var xmlChannelIdMap = map[int]string{
1005: "tv2.no",
1152: "zebra.tv2.no",
1969: "livsstil.tv2.no",
1147: "news.tv2.no",
1153: "sport1.tv2.no",
1154: "sport2.tv2.no",
1148: "sportpremium.tv2.no",
1000: "nrk1.nrk.no",
1001: "nrk2.nrk.no",
1112: "nrk3.nrk.no",
1041: "tv3.no",
1169: "v4.no",
1162: "tvnorge.no",
1101: "max.no",
1092: "fem.no",
1176: "vox.no",
1132: "svt1.svt.se",
1134: "svt2.svt.se",
1156: "tv4.se",
1078: "dr1.dr.dk",
1079: "dr2.dr.dk",
1083: "tv2.dk",
1175: "tv6.no",
1093: "foxtv.no",
1050: "bbcworld.no",
1046: "bbcentertainment.no",
1048: "bbcknowledge.no",
1044: "animalplanet.discovery.eu",
1072: "hd.discovery.no",
1073: "discovery.no",
1080: "science.discovery.no",
1085: "world.discovery.no",
1094: "historytv.no",
1105: "natgeo.no",
1108: "wild.natgeo.no",
1138: "travelchannel.no",
1082: "tlc.discovery.no",
1088: "eurosport.discovery.no",
1089: "eurosport2.discovery.no",
1081: "dsf.de", // tysk sportskanal lol
1091: "extremesports.com",
1057: "first.cmore.no",
1059: "series.cmore.no",
1058: "hits.cmore.no",
1054: "stars.cmore.no",
1055: "emotion.cmore.no",
1060: "sf.cmore.no",
1062: "tennis.cmore.no",
1065: "hockey.cmore.no",
1140: "film.viasat.no",
9999: "action.film.viasat.no",
1141: "classic.film.viasat.no",
1142: "drama.film.viasat.no",
1143: "family.film.viasat.no",
1144: "comedy.film.viasat.no",
1174: "plus.viasport.no",
1170: "1.viasport.no",
1173: "2.viasport.no",
1172: "3.viasport.no",
1166: "golf.viasat.no",
1167: "history.viasat.no",
1165: "explore.viasat.no",
1168: "nature.viasat.no",
1103: "mtv.no",
1163: "vh1.no",
1164: "classic.vh1.no",
1113: "super.nrk.no",
1074: "disneychannel.no",
1077: "xd.disneychannel.no", // finnes ikke lengre
1075: "junior.disneychannel.no",
1110: "nickelodeon.no",
1051: "boomerang.no",
1067: "cartoonnetwork.no",
1043: "aljazeera.eu",
1071: "cnn.eu",
1069: "cnbc.eu",
1129: "skynews.eu",
1042: "3sat.de",
1084: "dw.de",
1178: "rai1.de",
1124: "rtl.de",
1158: "tv5.eu",
}
Loading

0 comments on commit 294f922

Please sign in to comment.