# Metalove

[Online Documentation](

Metalove is an Elixir Application to scrape podcast RSS feeds to extract and provide as much of the available metadata as possible. This includes relevant ID3 tag parsing to extract chapter, link and image metadata.

Metalove is intended to be a stateful live repository caching the scraped data. A one shot mode to just get one specific feed/metadata is also provided.

## Basic Usage

Use the main Metalove module to trigger scraping of the urls you like. Then use the hierarchy of structs/modules to access them. 

A `Metalove.Podcast` can reference many `Metalove.PodcastFeed`s which in turn have `Metalove.Episode`s with `Metalove.Enclosure`s. Once scraped, `PodcastFeed`s and their `Episode`s can be fetched using their corresponding `get_…` functions.

iex> feed_or_website_url = ""
iex> podcast = Metalove.get_podcast(feed_or_website_url)
	created_at: #DateTime<2019-02-23 13:09:48.632101Z>,
	feed_urls: ["",
	id: "",
	main_feed_url: "",
	updated_at: #DateTime<2019-02-23 13:23:10.917299Z>
iex> feed = Metalove.PodcastFeed.get_by_feed_url(podcast.main_feed_url)
iex> most_recent_episode = Metalove.Episode.get_by_episode_id(hd(feed.episodes))

## Mix Tasks

### `ml.chapter`

Parses the ID3 tag of an mp3 url or file, writes out the images and the podlove simple chapter tags. E.g.

$ mix ml.chapter --base-url -o /tmp --formats psc,json,mp4chaps
Extracted: /tmp/Chapter01.png
Extracted: /tmp/Chapter03.jpeg
Extracted: /tmp/Chapter05.jpeg
Extracted: /tmp/Chapter06.jpeg
Extracted: /tmp/Chapter07.jpeg
Found: 15 Chapters, 12 URLs and 5 Chapter Images
Wrote: psc to /tmp/Chapters.psc.xml
Wrote: json to /tmp/ChaptersFragment.json
Wrote: mp4chaps to /tmp/Chapters.mp3chaps.txt

<?xml version="1.0" encoding="UTF-8"?>
<psc:chapters version="1.2" xmlns:psc="">
  <psc:chapter start="00:00:00.000" title="ATP_progrm_chptr()" image=""/>
  <psc:chapter start="00:09:12.500" title="Follow-up: Apple-Facebook" href=""/>
  <psc:chapter start="00:12:12.000" title="Follow-up: FaceTime bug" href="" image=""/>
  <psc:chapter start="00:14:54.979" title="Sponsor: Eero (code ATP)" href=""/>
  <psc:chapter start="00:16:44.107" title='USB-C "MagSafe"' href="" image=""/>
  <psc:chapter start="00:20:43.000" title="USB-C LED charging cable" href="" image=""/>
  <psc:chapter start="00:22:01.500" title="Screen-protector update" href="" image=""/>
  <psc:chapter start="00:27:20.500" title="Sponsor: Molekule (code ATP)" href=""/>
  <psc:chapter start="00:29:02.500" title="Ahrendts leaving Apple" href=""/>
  <psc:chapter start="01:12:09.331" title="Sponsor: Squarespace (code ATP)" href=""/>
  <psc:chapter start="01:13:31.500" title="#askatp: Hard-drive brands" href=""/>
  <psc:chapter start="01:21:13.500" title="#askatp: Reopening windows"/>
  <psc:chapter start="01:26:41.500" title="#askatp: Gimlet-Spotify" href=""/>
  <psc:chapter start="01:46:40.500" title="Ending theme" href=""/>
  <psc:chapter start="01:47:43.500" title="Gas station update"/>

[{"start":"00:00:00.000","title":"ATP_progrm_chptr()","image":""},{"start":"00:09:12.500","title":"Follow-up: Apple-Facebook","href":""},{"start":"00:12:12.000","title":"Follow-up: FaceTime bug","href":"","image":""},{"start":"00:14:54.979","title":"Sponsor: Eero (code ATP)","href":""},{"start":"00:16:44.107","title":"USB-C \"MagSafe\"","href":"","image":""},{"start":"00:20:43.000","title":"USB-C LED charging cable","href":"","image":""},{"start":"00:22:01.500","title":"Screen-protector update","href":"","image":""},{"start":"00:27:20.500","title":"Sponsor: Molekule (code ATP)","href":""},{"start":"00:29:02.500","title":"Ahrendts leaving Apple","href":""},{"start":"01:12:09.331","title":"Sponsor: Squarespace (code ATP)","href":""},{"start":"01:13:31.500","title":"#askatp: Hard-drive brands","href":""},{"start":"01:21:13.500","title":"#askatp: Reopening windows"},{"start":"01:26:41.500","title":"#askatp: Gimlet-Spotify","href":""},{"start":"01:46:40.500","title":"Ending theme","href":""},{"start":"01:47:43.500","title":"Gas station update"}]

00:00:00.000 ATP_progrm_chptr()
00:09:12.500 Follow-up: Apple-Facebook <>
00:12:12.000 Follow-up: FaceTime bug <>
00:14:54.979 Sponsor: Eero (code ATP) <>
00:16:44.107 USB-C "MagSafe" <>
00:20:43.000 USB-C LED charging cable <>
00:22:01.500 Screen-protector update <>
00:27:20.500 Sponsor: Molekule (code ATP) <>
00:29:02.500 Ahrendts leaving Apple <>
01:12:09.331 Sponsor: Squarespace (code ATP) <>
01:13:31.500 #askatp: Hard-drive brands <>
01:21:13.500 #askatp: Reopening windows
01:26:41.500 #askatp: Gimlet-Spotify <>
01:46:40.500 Ending theme <>
01:47:43.500 Gas station update

### `ml.podcast`

Output a human friendly summary for the podcast found at the url given.

$ mix ml.podcast

Main Feed:

          Subtitle: Get all your WTF needs at
           Summary: Comedian Marc Maron is tackling the most complex philosophical question of our day - WTF? He'll get to the bottom of it with help from comedian friends, celebrity guests and the voices in his own head.
       Description: Comedian Marc Maron is tackling the most complex philosophical question of our day - WTF? He'll get to the bottom of it with help from comedian friends, celebrity guests and the voices in his own head.
Episodes available: 60

S01E997: Episode 997 - Andrea Savage (01:24:17|2019-02-25)
   Andrea Savage visits the garage to talk about her show I'm Sorry, life with agents, Jason Mantzoukas, and being cut from The Groundlings.
 .mp3: (24.42 MB)

S01E996: Episode 996 - Jon Bernthal (01:40:59|2019-02-21)
   Jon Bernthal talks about The Punisher, The Walking Dead, Martin Scorsese, and how he went from heading down a bad path in life to salvation by way of acting.
 .mp3: (29.2 MB)

## Known issues

* Metalove currently caches all http requests and state quite ridiculously, and does not reevaluate them their own. As workaround until that is done correctly the `Metalove.purge/0` exists.
* Metalove currently logs a lot.

## License

Metalove is released under the MIT license - see the [LICENSE.txt](// file.

## Installation

The package can be installed by adding `metalove` to your list of dependencies in `mix.exs`:

def deps do
    {:metalove, "~> 0.3"}