From d77fc6d418e70bc1c58e9b512a299232e8b6f4ed Mon Sep 17 00:00:00 2001 From: DrMxrcy <58747968+DrMxrcy@users.noreply.github.com> Date: Mon, 28 Aug 2023 20:45:36 -0400 Subject: [PATCH] Add ViewTube (#323) * Add Viewtube * Test Config * Update Names * Updates Secure * Update docker-compose.yml * Config Placeholder * Update docker-compose.yml * Final Changes * Update Viewtube --- apps/viewtube/config.json | 16 +++++++ apps/viewtube/docker-compose.yml | 66 ++++++++++++++++++++++++++ apps/viewtube/metadata/description.md | 44 +++++++++++++++++ apps/viewtube/metadata/logo.jpg | Bin 0 -> 16316 bytes apps/viewtube/metadata/optional.md | 37 +++++++++++++++ 5 files changed, 163 insertions(+) create mode 100644 apps/viewtube/config.json create mode 100644 apps/viewtube/docker-compose.yml create mode 100644 apps/viewtube/metadata/description.md create mode 100644 apps/viewtube/metadata/logo.jpg create mode 100644 apps/viewtube/metadata/optional.md diff --git a/apps/viewtube/config.json b/apps/viewtube/config.json new file mode 100644 index 00000000..6be4953d --- /dev/null +++ b/apps/viewtube/config.json @@ -0,0 +1,16 @@ +{ + "$schema": "../schema.json", + "name": "ViewTube", + "port": 8180, + "available": true, + "exposable": true, + "id": "viewtube", + "tipi_version": 1, + "version": "0.12.2", + "categories": ["media"], + "description": "The open source, privacy-conscious way to enjoy your favorite YouTube content.", + "short_desc": "The open source, privacy-conscious way to enjoy your favorite YouTube content.", + "author": "ViewTube", + "source": "https://github.com/ViewTube/viewtube", + "form_fields": [] +} diff --git a/apps/viewtube/docker-compose.yml b/apps/viewtube/docker-compose.yml new file mode 100644 index 00000000..46f386f7 --- /dev/null +++ b/apps/viewtube/docker-compose.yml @@ -0,0 +1,66 @@ +version: '3' + +services: + viewtube: + restart: unless-stopped + container_name: viewtube + image: mauriceo/viewtube:0.12.2 + depends_on: + - viewtube-mongodb + - viewtube-redis + volumes: + - ${APP_DATA_DIR}/data/viewtube:/data + environment: + - VIEWTUBE_DATABASE_HOST=viewtube-mongodb + - VIEWTUBE_REDIS_HOST=viewtube-redis + - VIEWTUBE_SECURE=true + - VIEWTUBE_CORS_ORIGIN=${APP_PROTOCOL:-http}://${APP_DOMAIN} + # - VIEWTUBE_YOUTUBE_COOKIE= + # - VIEWTUBE_YOUTUBE_IDENTIFIER= + ports: + - ${APP_PORT}:8066 + networks: + - tipi_main_network + labels: + # Main + traefik.enable: true + traefik.http.middlewares.viewtube-web-redirect.redirectscheme.scheme: https + traefik.http.services.viewtube.loadbalancer.server.port: 8066 + # Web + traefik.http.routers.viewtube-insecure.rule: Host(`${APP_DOMAIN}`) + traefik.http.routers.viewtube-insecure.entrypoints: web + traefik.http.routers.viewtube-insecure.service: viewtube + traefik.http.routers.viewtube-insecure.middlewares: viewtube-web-redirect + # Websecure + traefik.http.routers.viewtube.rule: Host(`${APP_DOMAIN}`) + traefik.http.routers.viewtube.entrypoints: websecure + traefik.http.routers.viewtube.service: viewtube + traefik.http.routers.viewtube.tls.certresolver: myresolver + # Local domain + traefik.http.routers.viewtube-local-insecure.rule: Host(`viewtube.${LOCAL_DOMAIN}`) + traefik.http.routers.viewtube-local-insecure.entrypoints: web + traefik.http.routers.viewtube-local-insecure.service: viewtube + traefik.http.routers.viewtube-local-insecure.middlewares: viewtube-web-redirect + # Local domain secure + traefik.http.routers.viewtube-local.rule: Host(`viewtube.${LOCAL_DOMAIN}`) + traefik.http.routers.viewtube-local.entrypoints: websecure + traefik.http.routers.viewtube-local.service: viewtube + traefik.http.routers.viewtube-local.tls: true + + viewtube-mongodb: + container_name: viewtube-mongodb + restart: unless-stopped + image: mongo:5 + networks: + - tipi_main_network + volumes: + - ${APP_DATA_DIR}/data/db:/data/db + + viewtube-redis: + container_name: viewtube-redis + restart: unless-stopped + image: redis:7 + networks: + - tipi_main_network + volumes: + - ${APP_DATA_DIR}/data/redis:/data diff --git a/apps/viewtube/metadata/description.md b/apps/viewtube/metadata/description.md new file mode 100644 index 00000000..429a6626 --- /dev/null +++ b/apps/viewtube/metadata/description.md @@ -0,0 +1,44 @@ +ViewTube is an alternative YouTube frontend that lets you watch, search and discover YouTube videos without ads or tracking. It's built to be mobile and desktop friendly, with dark and light themes, and a touch-friendly video player with gestures. You can create an account separately from YouTube, read comments, watch playlists, subscribe to channels and receive push notifications for new uploads It's built using [Nuxt](https://nuxt.com/) and [Nest](https://nestjs.com/). + +You can find the documentation at [viewtube.wiki](https://viewtube.wiki) + +## Features + +- Watch videos without ads or tracking +- Built from the ground up to be mobile and desktop friendly +- Dark and light themes +- Touch friendly video player with gestures +- Supports loop, speed, autoplay and volume +- Create an account separately from Youtube +- Read comments +- Search for videos +- Watch playlists +- Subscribe to channels and see their latest uploads +- Receive push notifications for subscribed channels +- Integrated SponsorBlock support + +## Where does ViewTube get the data from? + +ViewTube does not use the official Youtube API. It instead scrapes the data from the website using a combination of custom built tools and the following open source libraries. + +- [node-ytdl-core](https://github.com/fent/node-ytdl-core) +- [node-ytsr](https://github.com/TimeForANinja/node-ytsr) +- [node-ytpl](https://github.com/TimeForANinja/node-ytpl) +- [yt-comment-scraper](https://github.com/FreeTubeApp/yt-comment-scraper) +- [yt-channel-info](https://github.com/FreeTubeApp/yt-channel-info) + +## Screenshots + +### Homepage + +[![Screenshot-Homepage](https://camo.githubusercontent.com/7ca1b34ee39d918f86a7043a3ffae08b574d5630975255eb8840536e7e169248/68747470733a2f2f692e6962622e636f2f476b35744b51372f6c78743179306d6b2e6a7067)](https://camo.githubusercontent.com/7ca1b34ee39d918f86a7043a3ffae08b574d5630975255eb8840536e7e169248/68747470733a2f2f692e6962622e636f2f476b35744b51372f6c78743179306d6b2e6a7067) + +### Video + +[![Screenshot-Video](https://camo.githubusercontent.com/07ecf2f4a9e61eb326d2125375f674020cbf97b1a998defdeb21fd8d1aa6f8f7/68747470733a2f2f692e6962622e636f2f52544c327633662f6732656a663777662e6a7067)](https://camo.githubusercontent.com/07ecf2f4a9e61eb326d2125375f674020cbf97b1a998defdeb21fd8d1aa6f8f7/68747470733a2f2f692e6962622e636f2f52544c327633662f6732656a663777662e6a7067) + +### Channel + +[![Screenshot-Channel](https://camo.githubusercontent.com/b50d3f852326d5436cc32507eb2ee48d036092ae1cba3bc61485a8a4661d0ffd/68747470733a2f2f692e6962622e636f2f68396d663179642f366a3435616f35722e6a7067)](https://camo.githubusercontent.com/b50d3f852326d5436cc32507eb2ee48d036092ae1cba3bc61485a8a4661d0ffd/68747470733a2f2f692e6962622e636f2f68396d663179642f366a3435616f35722e6a7067) + + diff --git a/apps/viewtube/metadata/logo.jpg b/apps/viewtube/metadata/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c51877cbedcdf828e38b6a074069a65c4ec28d3d GIT binary patch literal 16316 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