gst-kitchen 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +24 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +87 -0
- data/Rakefile +1 -0
- data/bin/gst-kitchen +45 -0
- data/gst-kitchen.gemspec +23 -0
- data/lib/gst-kitchen.rb +18 -0
- data/lib/gst-kitchen/auphonic.rb +2 -0
- data/lib/gst-kitchen/auphonic/account.rb +33 -0
- data/lib/gst-kitchen/auphonic/production.rb +22 -0
- data/lib/gst-kitchen/episode.rb +74 -0
- data/lib/gst-kitchen/media.rb +60 -0
- data/lib/gst-kitchen/podcast.rb +112 -0
- data/lib/gst-kitchen/version.rb +3 -0
- data/templates/episodes.rss.erb +50 -0
- metadata +116 -0
data/.gitignore
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
|
19
|
+
# my playground
|
20
|
+
sandbox.rb
|
21
|
+
media
|
22
|
+
episodes
|
23
|
+
episodes*rss
|
24
|
+
podcast.yml
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sebastian Cohnen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Geekstammtisch's Podcast Kitchen (gst-kitchen)
|
2
|
+
|
3
|
+
Publishing podcats like a nerd!
|
4
|
+
|
5
|
+
This gem helps you to publish podcasts using Auphonic. It can fetch a list of Auphonic productions using
|
6
|
+
their API. You can add episodes and generate seperated feeds per audio format.
|
7
|
+
|
8
|
+
The Geekstammtisch website and this gem is inspired by [fanboys-IGOR] [igor].
|
9
|
+
|
10
|
+
**Note** that there might be some Geekstammtisch specific behavior left in this gem. If you find something,
|
11
|
+
drop me a note!
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gem file:
|
17
|
+
|
18
|
+
gem 'gst-kitchen'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install gst-kitchen
|
27
|
+
|
28
|
+
|
29
|
+
## Conventions
|
30
|
+
|
31
|
+
gst-kitchen assumes various conventions about (file) naming and URLs.
|
32
|
+
|
33
|
+
* feeds: feeds must be located at: `<website_url>/episodes.<format_file_ext>.rss`, e.g. `http://geekstammtisch.de/episodes.m4a.rss`
|
34
|
+
* episode media files must be located at: `<media_url>/<downcased handle><padded episode_nr>.<format_file_ext>`, e.g. `http://media.geekstammtisch.de/episodes/gst000.m4a`
|
35
|
+
|
36
|
+
Meta data from each episodes is read from your Auphonic production. The episode number is read from the `title`,
|
37
|
+
which must start with `<handle><number>`. The episode name is read from `subtitle`, summary and description is
|
38
|
+
set to Auphonic's `summary` field. Filesizes, playtime etc. is also read from the production.
|
39
|
+
|
40
|
+
|
41
|
+
## Usage
|
42
|
+
|
43
|
+
First you need to place your Auphonic credentials as JSON into `~/.auphonic`:
|
44
|
+
|
45
|
+
echo '{"user": "joe@example.com", "pass": "secret"}' > ~/.auphonic
|
46
|
+
|
47
|
+
Then you need to create a `podcast.yml` containing your podcast metadata.
|
48
|
+
You can take a look at https://github.com/tisba/gst-website/blob/master/podcast.yml as an example.
|
49
|
+
Important fields are
|
50
|
+
|
51
|
+
* basic meta data like, `title`, `subtutle`, `author`, `email` and `language`
|
52
|
+
* `handle` is a short *handle* for your podcast. It can be an abbreviation or acronym, or anything you like. For geekstammtisch it's `GST`.
|
53
|
+
* base URLs for the website and media location
|
54
|
+
* list of available audio formats: fileext_encoding, e.g. `m4a_aac` or `mp3_mp3`
|
55
|
+
* `rss_output_path` specifies where the generated feeds will be located
|
56
|
+
|
57
|
+
|
58
|
+
### CLI Usage
|
59
|
+
|
60
|
+
Get a list of all Auphonic productions
|
61
|
+
|
62
|
+
$ gst-kitchen list
|
63
|
+
|
64
|
+
Add a production to the podcast
|
65
|
+
|
66
|
+
$ gst-kitchen process --uuid=<PRODUCTION-UUID>
|
67
|
+
|
68
|
+
Render all configured feeds based on all episodes in `episodes/`
|
69
|
+
|
70
|
+
$ gst-kitchen feeds
|
71
|
+
|
72
|
+
|
73
|
+
### API Usage
|
74
|
+
|
75
|
+
**TBD**
|
76
|
+
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
1. Fork it
|
81
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
84
|
+
5. Create new Pull Request
|
85
|
+
|
86
|
+
|
87
|
+
[igor]: https://github.com/m4p/fanboys-IGOR "IGOR"
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/gst-kitchen
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
require "trollop"
|
5
|
+
require "gst-kitchen"
|
6
|
+
require "gst-kitchen/version"
|
7
|
+
|
8
|
+
require "fileutils"
|
9
|
+
|
10
|
+
SUB_COMMANDS = %w(feed process list version)
|
11
|
+
global_opts = Trollop::options do
|
12
|
+
banner "magic file deleting and copying utility"
|
13
|
+
opt :podcast, "path of podcast YAML specification", :default => "podcast.yml"
|
14
|
+
stop_on SUB_COMMANDS
|
15
|
+
end
|
16
|
+
|
17
|
+
case ARGV.shift
|
18
|
+
when "version"
|
19
|
+
puts GstKitchen::VERSION
|
20
|
+
when "feed"
|
21
|
+
subcmd_opts = Trollop::options do
|
22
|
+
end
|
23
|
+
Podcast.from_yaml(global_opts[:podcast]).render_all_feeds
|
24
|
+
when "list"
|
25
|
+
productions = Auphonic::Account.init_from_system.productions
|
26
|
+
productions.each do |production|
|
27
|
+
puts "#{production.meta["uuid"]} => #{production.meta["metadata"]["title"]}"
|
28
|
+
end
|
29
|
+
|
30
|
+
when "process"
|
31
|
+
subcmd_opts = Trollop::options do
|
32
|
+
opt :uuid, "Auphonic's production UUID", :type => :string
|
33
|
+
end
|
34
|
+
production = Auphonic::Account.init_from_system.production(subcmd_opts[:uuid])
|
35
|
+
|
36
|
+
podcast = Podcast.from_yaml("podcast.yml")
|
37
|
+
FileUtils.mkdir_p podcast.episodes_path
|
38
|
+
episode = podcast.create_episode_from_auphonic production
|
39
|
+
|
40
|
+
puts "Episode: #{episode}"
|
41
|
+
puts "Writing episode YAML to #{File.join(podcast.episodes_path, episode.handle.downcase)}.yml"
|
42
|
+
podcast.export_episode(episode)
|
43
|
+
else
|
44
|
+
Trollop::die "unknown subcommand #{subcmd.inspect}"
|
45
|
+
end
|
data/gst-kitchen.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gst-kitchen/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "gst-kitchen"
|
8
|
+
gem.version = GstKitchen::VERSION
|
9
|
+
gem.authors = ["Sebastian Cohnen"]
|
10
|
+
gem.email = ["sebastian.cohnen@gmx.net"]
|
11
|
+
gem.description = %q{gst-kitchen is a gem to publish podcasts like a nerd with auphonic!}
|
12
|
+
gem.summary = %q{gst-kitchen is a gem to publish podcasts like a nerd with auphonic!}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "yajl-ruby"
|
21
|
+
gem.add_dependency "trollop"
|
22
|
+
gem.add_dependency "rake"
|
23
|
+
end
|
data/lib/gst-kitchen.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "erb"
|
2
|
+
require "time"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
require "yajl"
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
require "gst-kitchen/version"
|
9
|
+
require "gst-kitchen/podcast"
|
10
|
+
require "gst-kitchen/episode"
|
11
|
+
require "gst-kitchen/media"
|
12
|
+
|
13
|
+
require "gst-kitchen/auphonic"
|
14
|
+
require "gst-kitchen/auphonic/production"
|
15
|
+
require "gst-kitchen/auphonic/account"
|
16
|
+
|
17
|
+
module GstKitchen
|
18
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Auphonic::Account
|
2
|
+
attr_reader :username, :password
|
3
|
+
|
4
|
+
def self.init_from_system
|
5
|
+
auphonic_credentials = Yajl::Parser.parse(File.read(File.expand_path("~/.auphonic")))
|
6
|
+
self.new(auphonic_credentials)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@username = options["user"]
|
11
|
+
@password = options["pass"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def production(uuid)
|
15
|
+
Auphonic::Production.new(self, uuid)
|
16
|
+
end
|
17
|
+
|
18
|
+
def productions
|
19
|
+
request("https://auphonic.com/api/productions.json")["data"].map do |meta|
|
20
|
+
production = Auphonic::Production.new(self)
|
21
|
+
production.meta = meta
|
22
|
+
production
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def request(url)
|
30
|
+
json = open(url, http_basic_authentication: [username, password])
|
31
|
+
Yajl::Parser.parse(json.read)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
|
3
|
+
class Auphonic::Production
|
4
|
+
attr_accessor :meta
|
5
|
+
|
6
|
+
def initialize(account, uuid=nil)
|
7
|
+
@account = account
|
8
|
+
fetch uuid if uuid
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def fetch(uuid)
|
15
|
+
@meta = request("https://auphonic.com/api/production/#{uuid}.json")
|
16
|
+
end
|
17
|
+
|
18
|
+
def request(url)
|
19
|
+
json = open(url, http_basic_authentication: [@account.username, @account.password])
|
20
|
+
Yajl::Parser.parse(json.read)
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
class Episode < Struct.new(:number, :name, :length, :media, :auphonic_uuid, :published_at, :summary, :description)
|
2
|
+
include Comparable
|
3
|
+
|
4
|
+
def self.from_auphonic(production)
|
5
|
+
data = production.meta
|
6
|
+
/GST(?<number>\d{3})/ =~ data["data"]["metadata"]["title"]
|
7
|
+
|
8
|
+
metadata = {
|
9
|
+
auphonic_uuid: data["data"]["uuid"],
|
10
|
+
number: number.to_i,
|
11
|
+
length: data["data"]["length"],
|
12
|
+
name: data["data"]["metadata"]["subtitle"].strip,
|
13
|
+
summary: data["data"]["metadata"]["summary"].strip,
|
14
|
+
description: data["data"]["metadata"]["summary"].strip
|
15
|
+
}
|
16
|
+
|
17
|
+
media = data["data"]["output_files"].each_with_object({}) do |item, obj|
|
18
|
+
obj[item["format"]] = {
|
19
|
+
"size" => item["size"],
|
20
|
+
"file_ext" => item["ending"]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
episode = self.new
|
25
|
+
|
26
|
+
episode.number = metadata[:number]
|
27
|
+
episode.name = metadata[:name]
|
28
|
+
episode.length = metadata[:length].round
|
29
|
+
episode.auphonic_uuid = metadata[:auphonic_uuid]
|
30
|
+
episode.published_at = Time.now
|
31
|
+
episode.summary = metadata[:summary]
|
32
|
+
episode.description = metadata[:description]
|
33
|
+
episode.media = media
|
34
|
+
|
35
|
+
episode
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.from_yaml(yaml_file)
|
39
|
+
YAML.load_file(yaml_file)
|
40
|
+
end
|
41
|
+
|
42
|
+
def initialize(*args)
|
43
|
+
super
|
44
|
+
end
|
45
|
+
|
46
|
+
def <=>(other)
|
47
|
+
self.number <=> other.number
|
48
|
+
end
|
49
|
+
|
50
|
+
def title
|
51
|
+
"#{handle} - #{name}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def handle
|
55
|
+
"GST#{"%03i" % self.number}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def rfc_2822_date
|
59
|
+
self.published_at.rfc2822
|
60
|
+
end
|
61
|
+
|
62
|
+
def duration
|
63
|
+
hours = length / (60 * 60)
|
64
|
+
minutes = (length - hours * 60 * 60) / 60
|
65
|
+
seconds = length % 60
|
66
|
+
|
67
|
+
"#{"%02i" % hours}:#{"%02i" % minutes}:#{"%02i" % seconds}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
"#{title} (#{duration}) https://auphonic.com/engine/status/#{auphonic_uuid}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class Media
|
4
|
+
class Format < Struct.new(:format, :file_ext, :mime_type)
|
5
|
+
Mp3 = self.new("mp3", "mp3", "audio/mpeg")
|
6
|
+
M4a = self.new("aac", "m4a", "audio/x-m4a")
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.format(format)
|
10
|
+
case format
|
11
|
+
when :m4a_aac then Media::Format::M4a
|
12
|
+
when :mp3_mp3 then Media::Format::Mp3
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(file)
|
17
|
+
@file = file
|
18
|
+
@md5_digest = Digest::MD5.file(@file).hexdigest.force_encoding("UTF-8")
|
19
|
+
end
|
20
|
+
|
21
|
+
def length
|
22
|
+
media_info["length"].to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def title
|
26
|
+
media_info["title"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def file_size
|
30
|
+
@file_size ||= File.size(@file)
|
31
|
+
end
|
32
|
+
|
33
|
+
def duration
|
34
|
+
return @duration if @duration
|
35
|
+
|
36
|
+
hours = length / (60 * 60)
|
37
|
+
minutes = (length - hours * 60 * 60) / 60
|
38
|
+
seconds = length % 60
|
39
|
+
|
40
|
+
@duration = "#{"%02i" % hours}:#{"%02i" % minutes}:#{"%02i" % seconds}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def aquire_meta_data!
|
44
|
+
[:duration, :file_size].each { |m| send(m) }
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def media_info
|
50
|
+
return @media_info if @media_info
|
51
|
+
|
52
|
+
@media_info = TagLib::FileRef.open(@file) do |ref|
|
53
|
+
{
|
54
|
+
"title" => ref.tag.title,
|
55
|
+
"length" => ref.audio_properties.length
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,112 @@
|
|
1
|
+
class Podcast
|
2
|
+
attr_accessor :title,
|
3
|
+
:subtitle,
|
4
|
+
:author,
|
5
|
+
:email,
|
6
|
+
:language,
|
7
|
+
:summary,
|
8
|
+
:handle,
|
9
|
+
:website,
|
10
|
+
:cover,
|
11
|
+
:media_url,
|
12
|
+
:episodes,
|
13
|
+
:explicit,
|
14
|
+
:rss_output_path,
|
15
|
+
:episodes_path
|
16
|
+
|
17
|
+
attr_accessor :formats
|
18
|
+
|
19
|
+
def self.from_yaml(yaml_file="podcast.yml")
|
20
|
+
hash = YAML.load_file(yaml_file)
|
21
|
+
|
22
|
+
podcast = self.new
|
23
|
+
podcast.title = hash["title"]
|
24
|
+
podcast.subtitle = hash["subtitle"]
|
25
|
+
podcast.author = hash["author"]
|
26
|
+
podcast.email = hash["email"]
|
27
|
+
podcast.language = hash["language"]
|
28
|
+
podcast.summary = hash["summary"]
|
29
|
+
podcast.handle = hash["handle"]
|
30
|
+
podcast.website = hash["website"]
|
31
|
+
podcast.cover = hash["cover"]
|
32
|
+
podcast.media_url = hash["media_url"]
|
33
|
+
podcast.explicit = hash["explicit"] || false
|
34
|
+
podcast.formats = hash["formats"].map { |format| Media.format(format) }
|
35
|
+
podcast.episodes_path = hash["episodes_path"] || "episodes/"
|
36
|
+
podcast.rss_output_path = hash["rss_output_path"] || "."
|
37
|
+
|
38
|
+
podcast.load_episodes
|
39
|
+
|
40
|
+
podcast
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_episodes
|
44
|
+
self.episodes = Dir[File.join(self.episodes_path, "#{handle.downcase}*.yml")].map do |yml|
|
45
|
+
Episode.from_yaml(yml)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_episode_from_auphonic(production)
|
50
|
+
Episode.from_auphonic production
|
51
|
+
end
|
52
|
+
|
53
|
+
def feed_url(format)
|
54
|
+
url = URI(self.website)
|
55
|
+
url.path = "/#{rss_file(format)}"
|
56
|
+
url.to_s
|
57
|
+
end
|
58
|
+
|
59
|
+
def episode_media_url(episode, format)
|
60
|
+
url = URI(self.media_url)
|
61
|
+
url.path += "/#{episode.handle.downcase}.#{format.file_ext}"
|
62
|
+
url.to_s
|
63
|
+
end
|
64
|
+
|
65
|
+
def cover_url
|
66
|
+
url = URI(self.website)
|
67
|
+
url.path = self.cover
|
68
|
+
url.to_s
|
69
|
+
end
|
70
|
+
|
71
|
+
def deep_link_url(episode)
|
72
|
+
url = URI(self.website)
|
73
|
+
url.fragment = "#{episode.number}:"
|
74
|
+
url.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
def podcast
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def current_format
|
82
|
+
@current_format
|
83
|
+
end
|
84
|
+
|
85
|
+
def render_feed(format)
|
86
|
+
@current_format = format
|
87
|
+
template = ERB.new File.read(File.join(File.dirname(__FILE__), "../..", "templates/episodes.rss.erb"))
|
88
|
+
File.open(File.join(rss_output_path, rss_file(format)), "w") do |rss|
|
89
|
+
rss.write template.result(binding)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def export_episode(episode)
|
94
|
+
destination = File.join(episodes_path, "#{episode.handle.downcase}.yml")
|
95
|
+
File.open(destination, "w") { |file| file.write episode.to_yaml}
|
96
|
+
end
|
97
|
+
|
98
|
+
def render_all_feeds
|
99
|
+
self.formats.each do |format|
|
100
|
+
render_feed(format)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def other_formats(format)
|
105
|
+
self.formats - [format]
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def rss_file(format)
|
110
|
+
"episodes.#{format.file_ext}.rss"
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
|
3
|
+
<channel>
|
4
|
+
<title><%= podcast.title %></title>
|
5
|
+
<link><%= podcast.website %></link>
|
6
|
+
<atom:link rel="self" href="<%= podcast.feed_url(podcast.current_format) %>" type="application/rss+xml" title="<%= podcast.current_format.file_ext.upcase %> Audio"/>
|
7
|
+
<% podcast.other_formats(current_format).each do |format| %>
|
8
|
+
<atom:link rel="alternate" href="<%= podcast.feed_url(format) %>" type="application/rss+xml" title="<%= format.file_ext.upcase %> Audio"/>
|
9
|
+
<% end %>
|
10
|
+
<language><%= podcast.language %></language>
|
11
|
+
<generator>gst-kitchen</generator>
|
12
|
+
<copyright><%= podcast.author %>, cc-by-nc-sa</copyright>
|
13
|
+
<itunes:subtitle><%= podcast.subtitle %></itunes:subtitle>
|
14
|
+
<itunes:author><%= podcast.author %></itunes:author>
|
15
|
+
<managingEditor><%= podcast.email %> (<%= podcast.author %>)</managingEditor>
|
16
|
+
<itunes:summary><%= podcast.summary %></itunes:summary>
|
17
|
+
<itunes:explicit><%= podcast.explicit ? "yes" : "no" %></itunes:explicit>
|
18
|
+
<description><%= podcast.summary %></description>
|
19
|
+
<itunes:owner>
|
20
|
+
<itunes:name><%= podcast.author %></itunes:name>
|
21
|
+
<itunes:email><%= podcast.email %></itunes:email>
|
22
|
+
</itunes:owner>
|
23
|
+
|
24
|
+
<itunes:image href="<%= podcast.cover_url %>"/>
|
25
|
+
|
26
|
+
<itunes:category text="Technology"/>
|
27
|
+
<itunes:category text="Technology">
|
28
|
+
<itunes:category text="Gadgets"/>
|
29
|
+
</itunes:category>
|
30
|
+
<itunes:category text="Technology">
|
31
|
+
<itunes:category text="Tech News"/>
|
32
|
+
</itunes:category>
|
33
|
+
|
34
|
+
<% podcast.episodes.each do |episode| %>
|
35
|
+
<item>
|
36
|
+
<title><%= episode.title %></title>
|
37
|
+
<itunes:explicit><%= podcast.explicit ? "yes" : "no" %></itunes:explicit>
|
38
|
+
<itunes:author><%= podcast.author %></itunes:author>
|
39
|
+
<itunes:subtitle><%= episode.title %></itunes:subtitle>
|
40
|
+
<enclosure url="<%= podcast.episode_media_url(episode, current_format) %>" length="<%= episode.media[current_format.format]["size"] %>" type="<%= current_format.mime_type %>"/>
|
41
|
+
<guid isPermaLink="false"><%= episode.handle %></guid>
|
42
|
+
<pubDate><%= episode.rfc_2822_date %></pubDate>
|
43
|
+
<itunes:duration><%= episode.duration %></itunes:duration>
|
44
|
+
<itunes:summary><![CDATA[<%= episode.summary %>]]></itunes:summary>
|
45
|
+
<description><![CDATA[<%= episode.description %>]]></description>
|
46
|
+
<atom:link rel="http://podlove.org/deep-link" href="<%= podcast.deep_link_url(episode) %>" />
|
47
|
+
</item>
|
48
|
+
<% end %>
|
49
|
+
</channel>
|
50
|
+
</rss>
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gst-kitchen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sebastian Cohnen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: yajl-ruby
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: trollop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: gst-kitchen is a gem to publish podcasts like a nerd with auphonic!
|
63
|
+
email:
|
64
|
+
- sebastian.cohnen@gmx.net
|
65
|
+
executables:
|
66
|
+
- gst-kitchen
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- LICENSE.txt
|
73
|
+
- README.md
|
74
|
+
- Rakefile
|
75
|
+
- bin/gst-kitchen
|
76
|
+
- gst-kitchen.gemspec
|
77
|
+
- lib/gst-kitchen.rb
|
78
|
+
- lib/gst-kitchen/auphonic.rb
|
79
|
+
- lib/gst-kitchen/auphonic/account.rb
|
80
|
+
- lib/gst-kitchen/auphonic/production.rb
|
81
|
+
- lib/gst-kitchen/episode.rb
|
82
|
+
- lib/gst-kitchen/media.rb
|
83
|
+
- lib/gst-kitchen/podcast.rb
|
84
|
+
- lib/gst-kitchen/version.rb
|
85
|
+
- templates/episodes.rss.erb
|
86
|
+
homepage: ''
|
87
|
+
licenses: []
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ! '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
hash: -203743376280899826
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
segments:
|
108
|
+
- 0
|
109
|
+
hash: -203743376280899826
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 1.8.24
|
113
|
+
signing_key:
|
114
|
+
specification_version: 3
|
115
|
+
summary: gst-kitchen is a gem to publish podcasts like a nerd with auphonic!
|
116
|
+
test_files: []
|