{"id":29640692,"url":"https://github.com/alanaktion/mytube","last_synced_at":"2025-10-25T11:38:05.837Z","repository":{"id":39754893,"uuid":"285173390","full_name":"Alanaktion/mytube","owner":"Alanaktion","description":"A self-hostable video archive app","archived":false,"fork":false,"pushed_at":"2025-04-06T17:51:40.000Z","size":6104,"stargazers_count":4,"open_issues_count":6,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-06T18:34:56.387Z","etag":null,"topics":["floatplane","twitch","twitter","youtube"],"latest_commit_sha":null,"homepage":"https://mytube.phpizza.com","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Alanaktion.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-08-05T03:55:08.000Z","updated_at":"2025-04-06T17:51:43.000Z","dependencies_parsed_at":"2025-03-12T22:19:55.216Z","dependency_job_id":"78e096d4-1cf8-4e2a-8a45-f16d9bd359c0","html_url":"https://github.com/Alanaktion/mytube","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/Alanaktion/mytube","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Alanaktion%2Fmytube","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Alanaktion%2Fmytube/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Alanaktion%2Fmytube/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Alanaktion%2Fmytube/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Alanaktion","download_url":"https://codeload.github.com/Alanaktion/mytube/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Alanaktion%2Fmytube/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266379213,"owners_count":23920157,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-21T11:47:31.412Z","response_time":64,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["floatplane","twitch","twitter","youtube"],"created_at":"2025-07-21T21:03:53.119Z","updated_at":"2025-10-25T11:38:00.795Z","avatar_url":"https://github.com/Alanaktion.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MyTube\n\nA self-hostable video archive web app\n\n[![CI](https://github.com/Alanaktion/mytube/actions/workflows/ci.yml/badge.svg)](https://github.com/Alanaktion/mytube/actions/workflows/ci.yml)\n\n## Features\n\n- Import video, channel, and playlist metadata from several sources:\n    - YouTube\n    - Twitch\n    - Twitter\n    - Floatplane\n- Import metadata from web URLs, local filesystem, and video IDs\n- Browse imported data from an intuitive web UI\n- Download videos automatically with yt-dlp\n- Light/dark mode toggle\n- Multiple languages\n- Administrator interface for importing content\n- GraphQL API for accessing public content\n- Experimental mobile app built with Expo\n\n## Demo\n\nhttps://mytube.phpizza.com/\n\n## Requirements\n\n- [PHP](https://php.net) 8.2 or later with [Composer](https://getcomposer.org)\n- [MySQL](https://dev.mysql.com/downloads/) 8 (or any RDBMS supported by Laravel)\n- Web server with support for rewrites and following symbolic links ([nginx](https://nginx.org/en/) recommended)\n- [NodeJS](https://nodejs.org/en/) LTS 20 or later for building front-end assets\n- [ffmpeg](https://ffmpeg.org) for converting files and reading metadata\n\n## Setup\n\nThe basic setup involves installing Composer and npm dependencies, configuring the app with database and API credentials, and compiling the static web assets.\n\nInstall dependencies:\n\n```bash\ncomposer install --no-dev\nnpm ci\n```\n\nConfigure the app:\n\n```bash\ncp .env.example .env\nphp artisan key:generate\nvim .env # Add database credentials\n```\n\nCompile the assets and set up the database:\n\n```bash\nnpm run build\nphp artisan migrate\n```\n\nFrom here, you can set up your web server to point to the `public/` directory and the site should be live. For more information on the web server setup, see the [Laravel deployment documentation](https://laravel.com/docs/8.x/deployment).\n\n### Queues\n\nMany features require the ability to queue actions such as large imports and downloads, to run them asynchronously from the web UI.\n\nThis can work with just a database, but it works best if you have something like Redis installed. There are really only two required steps for a basic queue setup:\n\n1. Set the `QUEUE_CONNECTION` value in your `.env` file to whatever you want to use for queues. You can use `database` by default, or `redis` if you have that installed.\n2. Start a command-line process to run the queued jobs: `php artisan queue:work --queue=default,download`.\n\nIf you choose to use Redis, you may require additional changes to the Redis configuration in your `.env` file, but the defaults should work for a typical local installation.\n\nA production environment will likely work best with additional setup to ensure the queue workers stay running. See the [Laravel Queue Worker documentation](https://laravel.com/docs/queues#running-the-queue-worker) for more details. In particular, heavily-used environments may find value in running a separate worker for each queue, or running multiple download queues in parallel if the additional IO is not an issue.\n\nMake sure to restart your queue workers any time you update the app.\n\n### Search indexing\n\nBy default, MyTube uses SQL \"like\" queries to match content when searching. This works fine particularly for smaller databases with diverse content, but is limited in performance and flexibility.\n\nAlteratively, MyTube can use Meilisearch with Laravel Scout to index content and provide fast, robust searches. It is optional, but makes the search _much_ better and it's highly recommended that you use it.\n\n1. Install and start [Meilisearch](https://docs.meilisearch.com/learn/getting_started/installation.html)\n2. In your `.env` file, set `SCOUT_DRIVER=meilisearch`\n3. If you are running multiple instances of MyTube, set a unique index prefix with the `SCOUT_PREFIX` value in your `.env` file\n4. Initialize your search indexes: `php artisan search:index`\n    - Subsequent changes to content will be updated automatically, but you can use this command to force a re-index with `--force`.\n\n### Production optimization\n\nIf you're not running the application for development/contribution purposes, it's recommended to run in optimized production mode for the best performance and to avoid leaking sensitive information like API keys.\n\n1. In `.env`, set `APP_ENV=production` and `APP_DEBUG=false`\n2. Run `php artisan optimize` to pre-cache the configuration, routing, etc.\n\nYou will need to re-run `php artisan optimize` any time you update the app.\n\n## Administration\n\nThe web interface includes an administrative UI that offers basic functions for importing data. It's accessible at the `/admin` path on the app.\n\nYou can create an admin user from the command-line:\n\n```bash\nphp artisan user:add\n```\n\n## Importing data\n\nImporting data may require a usable API key or user account for some sources and some object types. In particular, most YouTube, Twitch, and Twitter imports require a related API Key, and Floatplane imports currently rely on a session ID from a logged-in user with access to the imported data.\n\n### Local video files\n\nYou can import existing video files from your local filesystem:\n\n```bash\nphp artisan import:filesystem \u003cdirectory\u003e\n```\n\nThis will recursively scan the given directory for files that include YouTube video IDs in their filenames, and will fetch and store metadata from those videos. The videos will only be recognized if they have the YouTube UUID right before the file extension, as is the default in `yt-dlp`.\n\nSome videos have ambiguous video IDs, so separating your files by source and specifying the --source option when importing is recommended. For example, Twitch videos may have an 11-character ID that is most likely a Twitch ID, but also matches the YouTube ID format. Separating the files before importing allows you to specify the correct source, improving import accuracy and performance.\n\nFor best browser support, files should be in MP4 containers, with H.264 video and AAC audio. To download videos in this compatible single-file format:\n\n```bash\nyt-dlp -f bv+ba[ext=m4a]/b[ext=mp4]/bv+ba/b \\\n    --merge-output-format mp4 \\\n    \u003cURL\u003e\n```\n\nThis will avoid video transcoding where possible, but may occasionally require re-encoding the audio stream (which requires `ffmpeg` to be available). Using only the `merge-output-format` option will usually work, but may not download the ideal source formats, requiring more transcoding and potentially a lower quality result.\n\n### Playlists\n\nPlaylists can be imported by their URLs, either from command-line or from the admin web UI.\n\nFor CLI:\n\n```bash\nphp artisan import:playlist-url \u003cplaylist URL/IDs\u003e\n```\n\n### Downloading videos\n\nAny YouTube videos that have metadata imported, but no local files (_e.g._ from the playlist import), can have videos downloaded automatically. This requires [yt-dlp](https://github.com/yt-dlp/yt-dlp) to be installed. You should also have `ffmpeg` installed for the best format compatibility.\n\nStarting the download of any videos missing local files can be started from the command-line:\n\n```bash\nphp artisan youtube:download-videos\n```\n\nTo configure where the videos are downloaded to, add a new line to `.env`:\n\n```ini\nYTDL_DOWNLOAD_DIR=/var/media/videos\n```\n\nYou can also specify the path to your yt-dlp executable if it is not included on your $PATH:\n\n```ini\nYTDL_PATH=/usr/local/bin/yt-dlp\n```\n\nKeep in mind that this involves downloading the video files from the source, and potentially re-encoding some incompatible audio streams. This can require significant network bandwidth, disk IO, and CPU in some cases. You should also be familiar with the service's terms of use, including usage of the API and website, to ensure your usage is not contradictory to those terms. The [yt-dlp](https://github.com/yt-dlp/yt-dlp) project may have additional information on these topics.\n\n## GraphQL API\n\nThe application provides a GraphQL API for accessing data in the archive. An example implementation of an API client is the [Expo-based mobile app](https://github.com/Alanaktion/mytube-exbo). Most access is not limited to authenticated users, but user-specific functionality will require a valid OAuth bearer token.\n\n### Examples\n\nThis example gets recent videos with some basic metadata, including the channel. The `page` argument is optional.\n\n```graphql\n{\n  videos(page: 1) {\n    data {\n      id\n      uuid\n      title\n      published_at\n      channel {\n        id\n        uuid\n        title\n      }\n    }\n    current_page\n    last_page\n    total\n  }\n}\n\n```\n\nThis example searches channels by title.\n\n```graphql\n{\n  channels(search: \"Example\") {\n    data {\n      id\n      uuid\n      title\n    }\n    current_page\n    last_page\n    total\n  }\n}\n```\n\nThis example gets a specific video.\n\n```graphql\n{\n  videos(uuid: \"PF4YxGsF1DY\") {\n    data {\n      title\n      published_at\n    }\n  }\n}\n```\n\nThis example gets a list of videos from a specific channel.\n\n```graphql\n{\n  videos(channel_id: 6) {\n    data {\n      title\n      published_at\n    }\n    current_page\n    last_page\n    total\n  }\n}\n```\n\nMany of these options can be combined. For example, you can search videos by title, and filter the result to a specific channel. Every result set is a paginated list, even if only a specific resource is selected (_e.g._ when the `id` or `uuid` argument is used).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falanaktion%2Fmytube","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falanaktion%2Fmytube","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falanaktion%2Fmytube/lists"}