Music transcoder!!
This commit is contained in:
		
						commit
						e48574b4ce
					
				
					 4 changed files with 413 additions and 0 deletions
				
			
		
							
								
								
									
										219
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								.gitignore
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,219 @@
 | 
				
			||||||
 | 
					# Byte-compiled / optimized / DLL files
 | 
				
			||||||
 | 
					__pycache__/
 | 
				
			||||||
 | 
					*.py[codz]
 | 
				
			||||||
 | 
					*$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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# UV
 | 
				
			||||||
 | 
					#   Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
 | 
				
			||||||
 | 
					#   This is especially recommended for binary packages to ensure reproducibility, and is more
 | 
				
			||||||
 | 
					#   commonly ignored for libraries.
 | 
				
			||||||
 | 
					# uv.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
 | 
				
			||||||
 | 
					# poetry.toml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pdm
 | 
				
			||||||
 | 
					#   Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
 | 
				
			||||||
 | 
					#   pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
 | 
				
			||||||
 | 
					#   https://pdm-project.org/en/latest/usage/project/#working-with-version-control
 | 
				
			||||||
 | 
					# pdm.lock
 | 
				
			||||||
 | 
					# pdm.toml
 | 
				
			||||||
 | 
					.pdm-python
 | 
				
			||||||
 | 
					.pdm-build/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# pixi
 | 
				
			||||||
 | 
					#   Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
 | 
				
			||||||
 | 
					# pixi.lock
 | 
				
			||||||
 | 
					#   Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
 | 
				
			||||||
 | 
					#   in the .venv directory. It is recommended not to include this directory in version control.
 | 
				
			||||||
 | 
					.pixi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
 | 
				
			||||||
 | 
					__pypackages__/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Celery stuff
 | 
				
			||||||
 | 
					celerybeat-schedule
 | 
				
			||||||
 | 
					celerybeat.pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Redis
 | 
				
			||||||
 | 
					*.rdb
 | 
				
			||||||
 | 
					*.aof
 | 
				
			||||||
 | 
					*.pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# RabbitMQ
 | 
				
			||||||
 | 
					mnesia/
 | 
				
			||||||
 | 
					rabbitmq/
 | 
				
			||||||
 | 
					rabbitmq-data/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ActiveMQ
 | 
				
			||||||
 | 
					activemq-data/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SageMath parsed files
 | 
				
			||||||
 | 
					*.sage.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Environments
 | 
				
			||||||
 | 
					.env
 | 
				
			||||||
 | 
					.envrc
 | 
				
			||||||
 | 
					.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/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Abstra
 | 
				
			||||||
 | 
					#   Abstra is an AI-powered process automation framework.
 | 
				
			||||||
 | 
					#   Ignore directories containing user credentials, local state, and settings.
 | 
				
			||||||
 | 
					#   Learn more at https://abstra.io/docs
 | 
				
			||||||
 | 
					.abstra/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Visual Studio Code
 | 
				
			||||||
 | 
					#   Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore 
 | 
				
			||||||
 | 
					#   that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
 | 
				
			||||||
 | 
					#   and can be added to the global gitignore or merged into this file. However, if you prefer, 
 | 
				
			||||||
 | 
					#   you could uncomment the following to ignore the entire vscode folder
 | 
				
			||||||
 | 
					# .vscode/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Ruff stuff:
 | 
				
			||||||
 | 
					.ruff_cache/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# PyPI configuration file
 | 
				
			||||||
 | 
					.pypirc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Marimo
 | 
				
			||||||
 | 
					marimo/_static/
 | 
				
			||||||
 | 
					marimo/_lsp/
 | 
				
			||||||
 | 
					__marimo__/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Streamlit
 | 
				
			||||||
 | 
					.streamlit/secrets.toml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Direnv
 | 
				
			||||||
 | 
					.direnv
 | 
				
			||||||
							
								
								
									
										61
									
								
								flake.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								flake.lock
									
										
									
										generated
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,61 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  "nodes": {
 | 
				
			||||||
 | 
					    "flake-utils": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "systems": "systems"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1731533236,
 | 
				
			||||||
 | 
					        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
 | 
				
			||||||
 | 
					        "owner": "numtide",
 | 
				
			||||||
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
 | 
					        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "numtide",
 | 
				
			||||||
 | 
					        "repo": "flake-utils",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "nixpkgs": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1759733170,
 | 
				
			||||||
 | 
					        "narHash": "sha256-TXnlsVb5Z8HXZ6mZoeOAIwxmvGHp1g4Dw89eLvIwKVI=",
 | 
				
			||||||
 | 
					        "owner": "NixOS",
 | 
				
			||||||
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
 | 
					        "rev": "8913c168d1c56dc49a7718685968f38752171c3b",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "NixOS",
 | 
				
			||||||
 | 
					        "ref": "nixos-unstable",
 | 
				
			||||||
 | 
					        "repo": "nixpkgs",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "root": {
 | 
				
			||||||
 | 
					      "inputs": {
 | 
				
			||||||
 | 
					        "flake-utils": "flake-utils",
 | 
				
			||||||
 | 
					        "nixpkgs": "nixpkgs"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "systems": {
 | 
				
			||||||
 | 
					      "locked": {
 | 
				
			||||||
 | 
					        "lastModified": 1681028828,
 | 
				
			||||||
 | 
					        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "original": {
 | 
				
			||||||
 | 
					        "owner": "nix-systems",
 | 
				
			||||||
 | 
					        "repo": "default",
 | 
				
			||||||
 | 
					        "type": "github"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "root": "root",
 | 
				
			||||||
 | 
					  "version": 7
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								flake.nix
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								flake.nix
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,26 @@
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					  inputs = {
 | 
				
			||||||
 | 
					    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
 | 
				
			||||||
 | 
					    flake-utils.url = "github:numtide/flake-utils";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  outputs = { self, nixpkgs, flake-utils, ... }:
 | 
				
			||||||
 | 
					    flake-utils.lib.eachDefaultSystem (system:
 | 
				
			||||||
 | 
					      let
 | 
				
			||||||
 | 
					        pkgs = import nixpkgs {
 | 
				
			||||||
 | 
					          inherit system;
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      in
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        devShells.default = pkgs.mkShell rec {
 | 
				
			||||||
 | 
					          buildInputs = [
 | 
				
			||||||
 | 
					            pkgs.opusTools
 | 
				
			||||||
 | 
					            (pkgs.python3.withPackages (python-pkgs: with python-pkgs; [
 | 
				
			||||||
 | 
					              black
 | 
				
			||||||
 | 
					              click
 | 
				
			||||||
 | 
					            ]))
 | 
				
			||||||
 | 
					          ];
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								music_transcoder/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								music_transcoder/__main__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					from dataclasses import dataclass
 | 
				
			||||||
 | 
					import click
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					INPUT_FILE_EXTS_OPUSENC = [
 | 
				
			||||||
 | 
					    ".flac",
 | 
				
			||||||
 | 
					    ".wav",
 | 
				
			||||||
 | 
					    ".aiff",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					INPUT_FILE_EXTS_COPY = [
 | 
				
			||||||
 | 
					    ".opus",
 | 
				
			||||||
 | 
					    ".ogg",  # this can also contain FLAC (fry about it)
 | 
				
			||||||
 | 
					    ".mp3",
 | 
				
			||||||
 | 
					    ".m4a",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_opusenc_args(
 | 
				
			||||||
 | 
					    input_path: str,
 | 
				
			||||||
 | 
					    output_path: str,
 | 
				
			||||||
 | 
					    bitrate: int = 192,
 | 
				
			||||||
 | 
					) -> list[str]:
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					        "opusenc",
 | 
				
			||||||
 | 
					        "--bitrate",
 | 
				
			||||||
 | 
					        str(bitrate),
 | 
				
			||||||
 | 
					        "--music",
 | 
				
			||||||
 | 
					        input_path,
 | 
				
			||||||
 | 
					        output_path,
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@dataclass
 | 
				
			||||||
 | 
					class InputFile:
 | 
				
			||||||
 | 
					    filepath: str
 | 
				
			||||||
 | 
					    relpath: str
 | 
				
			||||||
 | 
					    relpath_noext: str
 | 
				
			||||||
 | 
					    transcode: bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@click.option(
 | 
				
			||||||
 | 
					    "--input-dir",
 | 
				
			||||||
 | 
					    "-i",
 | 
				
			||||||
 | 
					    type=click.Path(exists=True, dir_okay=True, file_okay=False, resolve_path=True),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					@click.option(
 | 
				
			||||||
 | 
					    "--output-dir",
 | 
				
			||||||
 | 
					    "-o",
 | 
				
			||||||
 | 
					    type=click.Path(
 | 
				
			||||||
 | 
					        exists=False, dir_okay=True, file_okay=False, writable=True, resolve_path=True
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					@click.command()
 | 
				
			||||||
 | 
					def music_transcoder(input_dir, output_dir):
 | 
				
			||||||
 | 
					    input_files: list[InputFile] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for dirpath, _, filenames in os.walk(input_dir):
 | 
				
			||||||
 | 
					        for filename in filenames:
 | 
				
			||||||
 | 
					            _, ext = os.path.splitext(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            transcode: bool
 | 
				
			||||||
 | 
					            if ext in INPUT_FILE_EXTS_OPUSENC:
 | 
				
			||||||
 | 
					                transcode = True
 | 
				
			||||||
 | 
					            elif ext in INPUT_FILE_EXTS_COPY:
 | 
				
			||||||
 | 
					                transcode = False
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                print("[WARN] rejecting file:", dirpath, filename)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            filepath = os.path.join(dirpath, filename)
 | 
				
			||||||
 | 
					            relpath = os.path.relpath(filepath, input_dir)
 | 
				
			||||||
 | 
					            relpath_noext, _ = os.path.splitext(relpath)
 | 
				
			||||||
 | 
					            input_files.append(
 | 
				
			||||||
 | 
					                InputFile(
 | 
				
			||||||
 | 
					                    filepath=filepath,
 | 
				
			||||||
 | 
					                    relpath=relpath,
 | 
				
			||||||
 | 
					                    relpath_noext=relpath_noext,
 | 
				
			||||||
 | 
					                    transcode=transcode,
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for input_file in input_files:
 | 
				
			||||||
 | 
					        if input_file.transcode:
 | 
				
			||||||
 | 
					            output_path = os.path.join(output_dir, input_file.relpath_noext + ".opus")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            output_path = os.path.join(output_dir, input_file.relpath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if os.path.exists(output_path):
 | 
				
			||||||
 | 
					            print("[WARN] skipping existing file", output_path)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        output_path_dir, _ = os.path.split(output_path)
 | 
				
			||||||
 | 
					        os.makedirs(output_path_dir, exist_ok=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not input_file.transcode:
 | 
				
			||||||
 | 
					            print("[INFO] hardlinking lossy file →", output_path)
 | 
				
			||||||
 | 
					            os.link(input_file.filepath, output_path)
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        print("[INFO] transcoding lossless file →", output_path)
 | 
				
			||||||
 | 
					        opusenc_args = get_opusenc_args(input_file.filepath, output_path)
 | 
				
			||||||
 | 
					        subprocess.run(opusenc_args, check=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    music_transcoder()
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue