mirror of
				https://codeberg.org/ashley/poke
				synced 2025-07-17 16:52:11 +00:00 
			
		
		
		
	Merge pull request '(videobundler) implement streaming and fix unknown var issue' (#95) from nin0dev/poke:main into main
Reviewed-on: https://codeberg.org/ashley/poke/pulls/95
This commit is contained in:
		
						commit
						f875214bee
					
				
							
								
								
									
										170
									
								
								videobundler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								videobundler/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,170 @@ | ||||
| # Byte-compiled / optimized / DLL files | ||||
| __pycache__/ | ||||
| *.py[cod] | ||||
| *$py.class | ||||
| 
 | ||||
| # C extensions | ||||
| *.so | ||||
| 
 | ||||
| # Distribution / packaging | ||||
| .Python | ||||
| build/ | ||||
| develop-eggs/ | ||||
| dist/ | ||||
| downloads/ | ||||
| eggs/ | ||||
| .eggs/ | ||||
| lib/ | ||||
| lib64/ | ||||
| parts/ | ||||
| sdist/ | ||||
| var/ | ||||
| wheels/ | ||||
| share/python-wheels/ | ||||
| *.egg-info/ | ||||
| .installed.cfg | ||||
| *.egg | ||||
| MANIFEST | ||||
| 
 | ||||
| # PyInstaller | ||||
| #  Usually these files are written by a python script from a template | ||||
| #  before PyInstaller builds the exe, so as to inject date/other infos into it. | ||||
| *.manifest | ||||
| *.spec | ||||
| 
 | ||||
| # Installer logs | ||||
| pip-log.txt | ||||
| pip-delete-this-directory.txt | ||||
| 
 | ||||
| # Unit test / coverage reports | ||||
| htmlcov/ | ||||
| .tox/ | ||||
| .nox/ | ||||
| .coverage | ||||
| .coverage.* | ||||
| .cache | ||||
| nosetests.xml | ||||
| coverage.xml | ||||
| *.cover | ||||
| *.py,cover | ||||
| .hypothesis/ | ||||
| .pytest_cache/ | ||||
| cover/ | ||||
| 
 | ||||
| # Translations | ||||
| *.mo | ||||
| *.pot | ||||
| 
 | ||||
| # Django stuff: | ||||
| *.log | ||||
| local_settings.py | ||||
| db.sqlite3 | ||||
| db.sqlite3-journal | ||||
| 
 | ||||
| # Flask stuff: | ||||
| instance/ | ||||
| .webassets-cache | ||||
| 
 | ||||
| # Scrapy stuff: | ||||
| .scrapy | ||||
| 
 | ||||
| # Sphinx documentation | ||||
| docs/_build/ | ||||
| 
 | ||||
| # PyBuilder | ||||
| .pybuilder/ | ||||
| target/ | ||||
| 
 | ||||
| # Jupyter Notebook | ||||
| .ipynb_checkpoints | ||||
| 
 | ||||
| # IPython | ||||
| profile_default/ | ||||
| ipython_config.py | ||||
| 
 | ||||
| # pyenv | ||||
| #   For a library or package, you might want to ignore these files since the code is | ||||
| #   intended to run in multiple environments; otherwise, check them in: | ||||
| # .python-version | ||||
| 
 | ||||
| # pipenv | ||||
| #   According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||||
| #   However, in case of collaboration, if having platform-specific dependencies or dependencies | ||||
| #   having no cross-platform support, pipenv may install dependencies that don't work, or not | ||||
| #   install all needed dependencies. | ||||
| #Pipfile.lock | ||||
| 
 | ||||
| # poetry | ||||
| #   Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. | ||||
| #   This is especially recommended for binary packages to ensure reproducibility, and is more | ||||
| #   commonly ignored for libraries. | ||||
| #   https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control | ||||
| #poetry.lock | ||||
| 
 | ||||
| # pdm | ||||
| #   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. | ||||
| #pdm.lock | ||||
| #   pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it | ||||
| #   in version control. | ||||
| #   https://pdm.fming.dev/latest/usage/project/#working-with-version-control | ||||
| .pdm.toml | ||||
| .pdm-python | ||||
| .pdm-build/ | ||||
| 
 | ||||
| # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm | ||||
| __pypackages__/ | ||||
| 
 | ||||
| # Celery stuff | ||||
| celerybeat-schedule | ||||
| celerybeat.pid | ||||
| 
 | ||||
| # SageMath parsed files | ||||
| *.sage.py | ||||
| 
 | ||||
| # Environments | ||||
| .env | ||||
| .venv | ||||
| env/ | ||||
| venv/ | ||||
| ENV/ | ||||
| env.bak/ | ||||
| venv.bak/ | ||||
| 
 | ||||
| # Spyder project settings | ||||
| .spyderproject | ||||
| .spyproject | ||||
| 
 | ||||
| # Rope project settings | ||||
| .ropeproject | ||||
| 
 | ||||
| # mkdocs documentation | ||||
| /site | ||||
| 
 | ||||
| # mypy | ||||
| .mypy_cache/ | ||||
| .dmypy.json | ||||
| dmypy.json | ||||
| 
 | ||||
| # Pyre type checker | ||||
| .pyre/ | ||||
| 
 | ||||
| # pytype static type analyzer | ||||
| .pytype/ | ||||
| 
 | ||||
| # Cython debug symbols | ||||
| cython_debug/ | ||||
| 
 | ||||
| # PyCharm | ||||
| #  JetBrains specific template is maintained in a separate JetBrains.gitignore that can | ||||
| #  be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore | ||||
| #  and can be added to the global gitignore or merged into this file.  For a more nuclear | ||||
| #  option (not recommended) you can uncomment the following to ignore the entire idea folder. | ||||
| #.idea/ | ||||
| bin/ | ||||
| include/ | ||||
| lib64/ | ||||
| pyvenv.cfg | ||||
| *.m4a | ||||
| *.mp4 | ||||
| .env | ||||
| done.* | ||||
| @ -5,6 +5,7 @@ import string | ||||
| import os | ||||
| import random | ||||
| import subprocess | ||||
| from aiohttp.web import Response, FileResponse | ||||
| 
 | ||||
| app = web.Application() | ||||
| app.router._frozen = False | ||||
| @ -15,16 +16,27 @@ def get_random_string(length): | ||||
| 	result_str = "".join(random.choice(letters) for i in range(length)) | ||||
| 	return result_str | ||||
| 
 | ||||
| async def merge(request): | ||||
| async def run_command(cmd): | ||||
| 	# Create subprocess | ||||
| 	process = await asyncio.create_subprocess_shell( | ||||
| 		cmd, | ||||
| 		stdout=asyncio.subprocess.PIPE, | ||||
| 	) | ||||
| 	# Wait for the subprocess to finish | ||||
| 	stdout, stderr = await process.communicate() | ||||
| 	# Check for errors | ||||
| 	if process.returncode!= 0: | ||||
| 	# Log or handle the error | ||||
| 		print(f"Command '{args}' failed with return code {process.returncode}") | ||||
| 		return None | ||||
| 	# Decode stdout and return | ||||
| 	return stdout | ||||
| 
 | ||||
| async def merge(request: aiohttp.web.Request): | ||||
| 	# register params | ||||
| 	try: | ||||
| 		job_id = request.rel_url.query["id"] | ||||
| 		video_id: str = request.rel_url.query["id"] | ||||
| 		audio_itag: str = request.rel_url.query["audio_itag"] | ||||
| 		video_itag: str = request.rel_url.query["video_itag"] | ||||
| 	except: | ||||
| 		# no one gives a fuck | ||||
| 		_ = 0 | ||||
| 	video_id: str = request.rel_url.query["id"] | ||||
| 	audio_itag: str = request.rel_url.query["audio_itag"] | ||||
| 	video_itag: str = request.rel_url.query["video_itag"] | ||||
| 	# validate | ||||
| 	if " " in video_id or len(video_id) > 11: | ||||
| 		print(f"Video {video_id} flagged as invalid, dropping request") | ||||
| @ -35,27 +47,48 @@ async def merge(request): | ||||
| 	if not video_itag.isdigit(): | ||||
| 		print(f"Video itag {video_itag} flagged as invalid, dropping request") | ||||
| 		return | ||||
| 	if os.path.isfile(f"done.{job_id}"): | ||||
| 		return web.FileResponse( | ||||
| 			path=f"output.{job_id}.mp4" | ||||
| 	if "Firefox" in request.headers["User-Agent"]: | ||||
| 		# Sane browser that supports streaming | ||||
| 		 | ||||
| 		cmdline = f"ffmpeg -i \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={audio_itag}&local=true\" -i \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={video_itag}&local=true\" -c copy -f mp4 -movflags frag_keyframe+empty_moov -" | ||||
| 		process = await asyncio.create_subprocess_shell( | ||||
| 			cmdline, | ||||
| 			stdout=asyncio.subprocess.PIPE, | ||||
| 			stderr=asyncio.subprocess.PIPE | ||||
| 		) | ||||
| 	proc_audio = await asyncio.create_subprocess_shell( | ||||
| 		f"wget -O{job_id}.m4a \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={audio_itag}&local=true\"", | ||||
| 	) | ||||
| 	proc_video = await asyncio.create_subprocess_shell( | ||||
| 		f"wget -O{job_id}.mp4 \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={video_itag}&local=true\"" | ||||
| 	) | ||||
| 	await asyncio.gather(proc_audio.wait(), proc_video.wait()) | ||||
| 	proc_ffmpeg = await asyncio.create_subprocess_shell( | ||||
| 		f"ffmpeg -i {job_id}.m4a -i {job_id}.mp4 -c copy output.{job_id}.mp4" | ||||
| 	) | ||||
| 	await proc_ffmpeg.wait() | ||||
| 	f = open(f"done.{job_id}", "a") | ||||
| 	f.write(":3") | ||||
| 	f.close() | ||||
| 	return web.FileResponse( | ||||
| 		path=f"output.{job_id}.mp4" | ||||
| 	) | ||||
| 		response = web.StreamResponse(status=206, reason='OK', headers={ | ||||
| 			'Content-Type': 'application/octet-stream', | ||||
| 			'Transfer-Encoding': 'chunked', | ||||
| 			'Content-Disposition': 'inline' | ||||
| 		}) | ||||
| 		await response.prepare(request) | ||||
| 		try: | ||||
| 			while True: | ||||
| 				chunk = await process.stdout.readline() | ||||
| 				if not chunk: | ||||
| 					break | ||||
| 				await response.write(chunk) | ||||
| 		except Exception as e: | ||||
| 			 | ||||
| 			print(f"Error streaming FFmpeg output: {e}") | ||||
| 		#finally: | ||||
| 			#await response.write_eof() | ||||
| 	else: | ||||
| 		# Likely to be chromium browser, so to avoid browser shitting itself we download file | ||||
| 		job_id = f"{request.rel_url.query["id"]}_{request.rel_url.query["audio_itag"]}_{request.rel_url.query["video_itag"]}" | ||||
| 		if os.path.isfile(f"{job_id}.mp4"): | ||||
| 			return web.FileResponse( | ||||
| 				path=f"{job_id}.mp4" | ||||
| 			) | ||||
| 		cmdline = f"ffmpeg -i \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={audio_itag}&local=true\" -i \"https://eu-proxy.poketube.fun/latest_version?id={video_id}&itag={video_itag}&local=true\" -c:v copy -f mp4 -movflags frag_keyframe+empty_moov {job_id}.mp4" | ||||
| 		process = await asyncio.create_subprocess_shell( | ||||
| 			cmdline | ||||
| 		) | ||||
| 		await process.wait() | ||||
| 		if process.returncode != 0:                                                                                # Log or handle the error | ||||
| 			return None | ||||
| 		response = FileResponse(path=f"{job_id}.mp4") | ||||
| 		return response | ||||
| 
 | ||||
| async def ping(request): | ||||
| 	return web.Response(body='{"success": true}', content_type="application/json") | ||||
| @ -68,4 +101,4 @@ async def init_app(): | ||||
| if __name__ == '__main__': | ||||
| 	loop = asyncio.get_event_loop() | ||||
| 	app = loop.run_until_complete(init_app()) | ||||
| 	web.run_app(app, port=3030) | ||||
| 	web.run_app(app, port=3030) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Ashley ////
						Ashley ////