cpod

Yet another cron-friendly podcatcher

git clone https://git.8pit.net/cpod.git

  1// Copyright (C) 2013-2015 Sören Tempel
  2//
  3// This program is free software: you can redistribute it and/or modify
  4// it under the terms of the GNU General Public License as published by
  5// the Free Software Foundation, either version 3 of the License, or
  6// (at your option) any later version.
  7//
  8// This program is distributed in the hope that it will be useful,
  9// but WITHOUT ANY WARRANTY; without even the implied warranty of
 10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 11// GNU General Public License for more details.
 12//
 13// You should have received a copy of the GNU General Public License
 14// along with this program. If not, see <http://www.gnu.org/licenses/>.
 15
 16// Package opml implements a parser for OPML files.
 17// See also: http://dev.opml.org/spec2.html
 18package opml
 19
 20import (
 21	"encoding/xml"
 22	"golang.org/x/net/html/charset"
 23	"os"
 24	"time"
 25)
 26
 27// OPML version supported by this library.
 28const version = "2.0"
 29
 30// OPML represent an OPML document.
 31type OPML struct {
 32	// XML name.
 33	XMLName xml.Name `xml:"opml"`
 34
 35	// OPML standard version implemented by this file.
 36	Version string `xml:"version,attr"`
 37
 38	// Title of the OPML document.
 39	Title string `xml:"head>title"`
 40
 41	// Time the document was created.
 42	Created string `xml:"head>dateCreated"`
 43
 44	// Array of outlines, each represents a subscription.
 45	Outlines []Outline `xml:"body>outline"`
 46}
 47
 48// Outline represents an arbitrary OPML outline.
 49type Outline struct {
 50	// Text attribute, might contain HTML markup.
 51	Text string `xml:"text,attr"`
 52
 53	// Type of file found at the outline URL.
 54	Type string `xml:"type,attr"`
 55
 56	// Arbitrary outline URL.
 57	URL string `xml:"xmlUrl,attr"`
 58}
 59
 60// Create returns a new OPML document with the given title. However,
 61// this is just syntax sugar. A file is only written after a call Save,
 62// it's the callers responsibility to do so if desired.
 63func Create(title string) *OPML {
 64	return &OPML{
 65		Version: version,
 66		Title:   title,
 67		Created: time.Now().Format(time.RFC1123Z),
 68	}
 69}
 70
 71// Load reads an existing OPML document located at the given path.
 72func Load(path string) (o *OPML, err error) {
 73	file, err := os.Open(path)
 74	if err != nil {
 75		return
 76	}
 77	defer file.Close()
 78
 79	decoder := xml.NewDecoder(file)
 80	decoder.CharsetReader = charset.NewReaderLabel
 81
 82	if err = decoder.Decode(&o); err != nil {
 83		return
 84	}
 85
 86	return
 87}
 88
 89// Add appends a new outline to the OPML document, even if the outline
 90// is already a part of the document.
 91func (o *OPML) Add(text, ftype, url string) {
 92	outline := Outline{
 93		Text: text,
 94		Type: ftype,
 95		URL:  url,
 96	}
 97
 98	o.Outlines = append(o.Outlines, outline)
 99}
100
101// Save writes an indented version of the OPML document to the given
102// file path.
103func (o *OPML) Save(path string) error {
104	file, err := os.Create(path)
105	if err != nil {
106		return err
107	}
108
109	defer file.Close()
110	data, err := xml.MarshalIndent(o, "", "\t")
111	if err != nil {
112		return err
113	}
114
115	if _, err = file.WriteString(xml.Header); err != nil {
116		return err
117	}
118
119	if _, err = file.Write(data); err != nil {
120		return err
121	}
122
123	return err
124}