From e12f024c5dc08bc173366ea6f4dae8a80e3f8786 Mon Sep 17 00:00:00 2001 From: DrMxrcy <58747968+DrMxrcy@users.noreply.github.com> Date: Tue, 4 Apr 2023 17:06:11 -0400 Subject: [PATCH] Add PodFetch (#307) * Add Podfetch * Update Index * Resolve Changes --- README.md | 1 + apps/podfetch/config.json | 49 +++++++++++++++++++++ apps/podfetch/docker-compose.yml | 30 +++++++++++++ apps/podfetch/metadata/description.md | 61 ++++++++++++++++++++++++++ apps/podfetch/metadata/logo.jpg | Bin 0 -> 13605 bytes 5 files changed, 141 insertions(+) create mode 100644 apps/podfetch/config.json create mode 100644 apps/podfetch/docker-compose.yml create mode 100644 apps/podfetch/metadata/description.md create mode 100644 apps/podfetch/metadata/logo.jpg diff --git a/README.md b/README.md index 1b810269..4a16f9e3 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ This is the official repository for the Tipi App Store. It contains all the apps - [Photoprism](https://github.com/photoprism/photoprism) - AI-Powered Photos App for the Decentralized Web. We are on a mission to protect your freedom and privacy. - [Pihole](https://github.com/pi-hole/pi-hole) - A black hole for Internet advertisements - [Plex](https://github.com/plexinc/pms-docker) - Stream Movies & TV Shows +- [PodFetch](https://github.com/SamTV12345/PodFetch) - A sleek and efficient podcast downloader. - [Portainer](https://github.com/portainer/portainer) - Making Docker and Kubernetes management easy. - [PrivateBin](https://github.com/PrivateBin/PrivateBin) - A minimalist, open source online pastebin where the server has zero knowledge of pasted data - [Prowlarr](https://github.com/Prowlarr/Prowlarr/) - A torrent/usenet indexer manager/proxy diff --git a/apps/podfetch/config.json b/apps/podfetch/config.json new file mode 100644 index 00000000..c8cfdb39 --- /dev/null +++ b/apps/podfetch/config.json @@ -0,0 +1,49 @@ +{ + "$schema": "../schema.json", + "name": "PodFetch", + "port": 8177, + "available": true, + "exposable": true, + "id": "podfetch", + "tipi_version": 1, + "version": "v2:latest", + "categories": ["media"], + "description": "A sleek and efficient podcast downloader.", + "short_desc": "A sleek and efficient podcast downloader.", + "author": "SamTV12345", + "source": "https://github.com/SamTV12345/PodFetch", + "form_fields": [ + { + "type": "text", + "label": "PodFetch Username", + "max": 50, + "min": 3, + "required": true, + "env_variable": "PODFETCH_USERNAME" + }, + { + "type": "password", + "label": "PodFetch Password", + "max": 50, + "min": 8, + "required": true, + "env_variable": "PODFETCH_PASSWORD" + }, + { + "type": "text", + "label": "Podcast Index API Key", + "hint": "The API key sent to you via mail", + "placeholder": "", + "required": false, + "env_variable": "PODFETCH_PODINDEX_API_KEY" + }, + { + "type": "text", + "label": "Podcast Index API Secret", + "hint": "The API secret sent to you via mail", + "placeholder": "", + "required": false, + "env_variable": "PODFETCH_PODINDEX_API_SECRET" + } + ] +} \ No newline at end of file diff --git a/apps/podfetch/docker-compose.yml b/apps/podfetch/docker-compose.yml new file mode 100644 index 00000000..092584b6 --- /dev/null +++ b/apps/podfetch/docker-compose.yml @@ -0,0 +1,30 @@ +version: "3" + +services: + podfetch: + container_name: podfetch + image: samuel19982/podgrabv2:latest + ports: + - ${APP_PORT}:8000 + volumes: + - ${APP_DATA_DIR}/data/podfetch-db:/app/db + - ${ROOT_FOLDER_HOST}/media/data/podcasts:/app/podcasts + environment: + - BASIC_AUTH=true + - USERNAME=${PODFETCH_USERNAME} + - PASSWORD=${PODFETCH_PASSWORD} + - POLLING_INTERVAL=60 + - SERVER_URL=${APP_PROTOCOL:-http}://${APP_DOMAIN} + - PODINDEX_API_KEY="${PODFETCH_PODINDEX_API_KEY}" + - PODINDEX_API_SECRET="${PODFETCH_PODINDEX_API_SECRET}" + restart: unless-stopped + networks: + - tipi_main_network + labels: + traefik.enable: ${APP_EXPOSED} + traefik.http.routers.podfetch.rule: Host(`${APP_DOMAIN}`) + traefik.http.routers.podfetch.entrypoints: websecure + traefik.http.routers.podfetch.service: podfetch + traefik.http.routers.podfetch.tls.certresolver: myresolver + traefik.http.services.podfetch.loadbalancer.server.port: 8000 + diff --git a/apps/podfetch/metadata/description.md b/apps/podfetch/metadata/description.md new file mode 100644 index 00000000..c941d305 --- /dev/null +++ b/apps/podfetch/metadata/description.md @@ -0,0 +1,61 @@ +Podfetch is a self-hosted podcast manager. It is a web app that lets you download podcasts and listen to them online. It is written in Rust and uses React for the frontend. + +Every time a new commit is pushed to the main branch, a new docker image is built and pushed to docker hub. So it is best to use something like [watchtower](https://github.com/containrrr/watchtower) to automatically update the docker image. + + +# API Info + +Sign up for an [Podcast Index](https://api.podcastindex.org/signup) account to get an API key. +--- + +## Folder Info + +| Root Folder | Container Folder | +|---------------------------------------------|------------------| +| /runtipi/app-data/podfetch/data/podfetch-db | /app/db | +| /runtipi/media/data/podcasts:/app/podcasts | /app/podcasts | + +--- + +## UI + +## [](https://github.com/SamTV12345/PodFetch#audio-player)Audio Player + +The podcast listening tool contains an advanced audio player that can be used to listen to your podcasts,skip episodes, turn the volumes as high as 300% or skip around in the current episode. [![Audio Player](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/advanced_audio_player.png)](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/advanced_audio_player.png) + +# [](https://github.com/SamTV12345/PodFetch#continue-right-where-you-stopped)Continue right where you stopped + +The tool will automatically save your progress in the current episode and will resume from where you left off even if you close the browser. You can continue listening on all devices by just hitting play on any episode on your home screen. + +[![Continue listening to episodes](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/continue_listening.png)](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/continue_listening.png) + +## [](https://github.com/SamTV12345/PodFetch#search-for-podcasts)Search for podcasts + +You can search for podcast episodes by hitting CTRL+F and typing any word that might appear in the description or title of the podcast episode you want to listen to. [![Audio Player](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/search.png)](https://raw.githubusercontent.com/SamTV12345/podgrabv2/main/docs/search.png) + +## [](https://github.com/SamTV12345/PodFetch#internationalization)Internationalization + +Podfetch is currently available in English and German. If you want to add a new language you can do so by adding a new file to the `i18n` folder and adding the translations to the file. + +# [](https://github.com/SamTV12345/PodFetch#rss-feed)RSS feed + +Podfetch offers an own feed to download podcast episodes. You can add the url /rss to your favorite podcast app like gPodder to download and play episodes. +s +# [](https://github.com/SamTV12345/PodFetch#roadmap)Roadmap + +- [x] Add podcasts via Itunes API +- [x] Check for new episodes. +- [x] Download episodes. +- [x] Play episodes. +- [x] Force refresh download of podcast episodes. +- [x] Force refresh of podcast episodes. +- [x] Resume podcasts even if browser is closed. +- [x] Add websocket support for new podcasts. +- [x] Add detailed audio player. +- [x] Star podcasts. +- [x] Unsubscribe podcasts. +- [x] Add retrieving podcasts from Podcastindex.org. +- [x] Basic Auth. +- [x] Import from OPML file. +- [ ] Like episodes. +- [ ] Delete podcasts. \ No newline at end of file diff --git a/apps/podfetch/metadata/logo.jpg b/apps/podfetch/metadata/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fedcaa150228752cb06db8ab902c3940d576429f GIT binary patch literal 13605 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 literal 0 HcmV?d00001