{"id":25238087,"url":"https://github.com/tarponjargon/clipcast","last_synced_at":"2025-07-19T08:03:06.699Z","repository":{"id":266765359,"uuid":"898786690","full_name":"tarponjargon/clipcast","owner":"tarponjargon","description":"Convert news articles, blog posts (and more) into audio podcast episodes using natural-sounding AI text-to-speech models","archived":false,"fork":false,"pushed_at":"2025-02-24T14:48:41.000Z","size":25454,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-02T05:04:59.906Z","etag":null,"topics":["ai","flask","htmx","python3","text-to-speech","tts","webpack"],"latest_commit_sha":null,"homepage":"","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tarponjargon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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":"2024-12-05T03:10:56.000Z","updated_at":"2025-02-24T14:48:44.000Z","dependencies_parsed_at":null,"dependency_job_id":"68ba0015-8582-4962-9d92-0e6992707372","html_url":"https://github.com/tarponjargon/clipcast","commit_stats":null,"previous_names":["tarponjargon/clipcast"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tarponjargon/clipcast","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarponjargon%2Fclipcast","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarponjargon%2Fclipcast/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarponjargon%2Fclipcast/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarponjargon%2Fclipcast/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tarponjargon","download_url":"https://codeload.github.com/tarponjargon/clipcast/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tarponjargon%2Fclipcast/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265904222,"owners_count":23846673,"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","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":["ai","flask","htmx","python3","text-to-speech","tts","webpack"],"created_at":"2025-02-11T16:44:13.512Z","updated_at":"2025-07-19T08:03:06.688Z","avatar_url":"https://github.com/tarponjargon.png","language":"SCSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PROJECT OVERVIEW\n\nThis is a web application that accepts content in the form of links (or plain text), parses the content, converts to speech and places in each user's podcast feed.\n\nIt uses python/flask on the back end and Bootstrap and HTMX on the front end.\n\n[ClipCast.it](https://clipcast.it/)\n\n![screenshot 1](https://www.thewhiteroom.com/images/clipcast-screenshot.png)\n\n![screenshot 2](https://www.thewhiteroom.com/images/clipcast-screenshot2.png)\n\n## PREREQUISITES\n\n1.  [Docker](https://www.docker.com/) (dev environment)\n2.  [ngrok](https://www.ngrok.com/) (dev environment)\n3.  [direnv](https://direnv.net/)\n4.  [S3](https://www.cloudflare.com/developer-platform/solutions/s3-compatible-object-storage/)\n5.  [OpenAI API access](https://platform.openai.com/docs/overview) (Text-to-speech voice models)\n6.  [Amazon Polly API Access](https://docs.aws.amazon.com/polly/latest/dg/what-is.html) (if more voices are desired)\n7.  [Google TTS API Access](https://cloud.google.com/text-to-speech?hl=en) (if more voices are desired)\n\n## INSTALLATION\n\n1.  `cp .envrc.sample .envrc` and update all lines denoted with 'update' comment\n2.  `direnv allow`\n3.  Create a virtual environment `virtualenv -p $(which python3) virtualenv_python`\n4.  Install python packages `pip3 install -r requirements.txt`\n5.  Install all NPM modules `npm install`\n6.  Start everything `./start.sh`\n\nSince the ngrok static url is public, there's a password challenge:\n\nuser: misc\npass: misc\n\n## CONNECTING TO CONTAINERS\n\nUse following command to ssh to containers:\n\n`docker exec -it [CONTAINER NAME] /bin/bash`\n\nFor example, to connect to the clipcast-local container:\n\n`docker exec -it clipcast-local /bin/bash`\n\n## TAILING LOGS\n\nYou'll probably want to know what the output of the stuff in the containers is, particularly clipcast-local\n\n`docker logs --follow clipcast-local`\n\n## ADDING NPM PACKAGES\n\nwebpack lives outside of docker, so no special docker command needed. Shut down the instance and run this in project directory:\n\n`npm install [PACKAGE]`\n\n## ADDING PYTHON PACKAGES\n\nNot straightforward because the packages live locally in the virtual environment as well as in the container. While the\ncontainers are running, in another terminal do this from project dir (replace [PACKAGE] with name of package you're installing):\n\n`pip3 install [PACKAGE]; pip3 freeze \u003e requirements.txt; docker exec -it clipcast-local pip3 install -r requirements.txt`\n\nunfortunately you have to re-create the image if you want the package there next time you start\n\n## FLASK INTERACTIVE SHELL\n\nfor development you can use the flask interactive shell REPL. Unfortunately it does not live-reload when file changes are made.\nFrom WITHIN the docker container:\n\n`flask shell`\n`ctx = app.test_request_context()`\n`ctx.push()`\n\nThen do imports:\n\n`from flask_app.modules.tts.openai_tts import OpenAITTS`\n\nand call functions:\n\n`OpenAITTS(\"/project/tmp/tests.mp3\", \"Thank you for using clipcast\", “fable”).synthesize_speech()`\n\n## DEBUGGING URL FETCHES\n\nto try to figure out why \"content not found\" happens for certain urls, here are ways to run the 2 fetching\nmethods in the REPL\n\n`flask shell`\n\nfrom playwright.sync_api import sync_playwright, Error\n\nurl = \"https://techxplore.com/news/2025-02-indiana-jones-jailbreak-approach-highlights.html\"\nfetch_timeout=8000\ncustom_headers = {\n\"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36\",\n\"Accept-Language\": 'en-US,en;q=0.9'\n}\nwith sync_playwright() as p:\nbrowser = p.chromium.launch(headless=True)\ncontext = browser.new_context(extra_http_headers=custom_headers)\nbrowser = p.chromium.launch(headless=True)\npage = context.new_page()\npage.goto(url, timeout=fetch_timeout)\npage.wait_for_load_state(\"networkidle\", timeout=fetch_timeout)\nhtml_source = page.content()\nprint(html_source)\nbrowser.close()\n\n# with \"requests\"\n\nimport requests\nurl=\"https://techxplore.com/news/2025-02-indiana-jones-jailbreak-approach-highlights.html\"\nresponse = requests.get(url, timeout=8000)\nresponse.raise_for_status()\nprint(response.text)\n\n## TESTING\n\nTesting is with Playwright\n\n`npx playwright test --workers=1 --ui --headed --debug`\nFor deveoping tests\n\n`npx playwright test --workers=1 --trace=on --project=chromium`\nrun all tests headless just with chromium\n\n`npx playwright test --workers=1`\nRuns the end-to-end tests.\n\n`npx playwright test --workers=1 e2e/03_add_episode.spec.js --project=webkit --trace=on`\nruns a specific test with a specific browser\n\n`npx playwright test --ui --workers=1`\nStarts the interactive UI mode.\n\n`npx playwright test example --workers=1`\nRuns the tests in a specific file.\n\n`npx playwright test --debug --workers=1`\nRuns the tests in debug mode.\n\n`npx playwright codegen`\nAuto generate tests with Codegen.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarponjargon%2Fclipcast","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftarponjargon%2Fclipcast","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftarponjargon%2Fclipcast/lists"}