From c0ce9c88488942587fff40726ea4aad2e5926daa Mon Sep 17 00:00:00 2001 From: sHa Date: Sat, 27 Dec 2025 03:14:11 +0000 Subject: [PATCH] feat: Add developer guide, enhance versioning and release process, and refactor extractor imports --- DEVELOP.md | 149 ++++++++++++++++++++++++++ README.md | 69 +----------- dist/renamer-0.2.5-py3-none-any.whl | Bin 32499 -> 33387 bytes pyproject.toml | 2 + renamer/__init__.py | 2 +- renamer/app.py | 2 +- renamer/bump.py | 15 +++ renamer/{ => extractors}/extractor.py | 10 +- renamer/release.py | 22 ++++ 9 files changed, 197 insertions(+), 74 deletions(-) create mode 100644 DEVELOP.md create mode 100644 renamer/bump.py rename renamer/{ => extractors}/extractor.py (95%) create mode 100644 renamer/release.py diff --git a/DEVELOP.md b/DEVELOP.md new file mode 100644 index 0000000..eab4572 --- /dev/null +++ b/DEVELOP.md @@ -0,0 +1,149 @@ +# Developer Guide + +This guide contains information for developers working on the Renamer project. + +## Development Setup + +### Prerequisites +- Python 3.11+ +- UV package manager + +### Install UV (if not already installed) +```bash +curl -LsSf https://astral.sh/uv/install.sh | sh +``` + +### Development Installation +```bash +# Clone the repository +git clone +cd renamer + +# Install in development mode with all dependencies +uv sync + +# Install the package in editable mode +uv pip install -e . +``` + +### Running in Development +```bash +# Run directly from source +uv run python renamer/main.py + +# Or run with specific directory +uv run python renamer/main.py /path/to/directory + +# Or use the installed command +uv run renamer +``` + +## Development Commands + +The project includes several development commands defined in `pyproject.toml`: + +### bump-version +Increments the patch version in `pyproject.toml` (e.g., 0.2.6 → 0.2.7). +```bash +uv run bump-version +``` + +### release +Runs a batch process: bump version, sync dependencies, and build the package. +```bash +uv run release +``` + +### Other Commands +- `uv sync`: Install/update dependencies +- `uv build`: Build the package +- `uv run pytest`: Run tests + +## Debugging + +### Formatter Logging +Enable detailed logging for formatter operations: +```bash +FORMATTER_LOG=1 uv run renamer /path/to/directory +``` + +This creates `formatter.log` with: +- Formatter call sequences and ordering +- Input/output values for each formatter +- Caller information (file and line number) +- Any errors during formatting + +## Architecture + +The application uses a modular architecture: + +### Extractors (`renamer/extractors/`) +- **MediaInfoExtractor**: Extracts detailed track information using PyMediaInfo +- **FilenameExtractor**: Parses metadata from filenames +- **MetadataExtractor**: Extracts embedded metadata using Mutagen +- **FileInfoExtractor**: Provides basic file information +- **DefaultExtractor**: Fallback extractor +- **MediaExtractor**: Main extractor coordinating all others + +### Formatters (`renamer/formatters/`) +- **MediaFormatter**: Formats extracted data for display +- **ProposedNameFormatter**: Generates intelligent rename suggestions +- **TrackFormatter**: Formats video/audio/subtitle track information +- **SizeFormatter**: Formats file sizes +- **DateFormatter**: Formats timestamps +- **DurationFormatter**: Formats time durations +- **ResolutionFormatter**: Formats video resolutions +- **TextFormatter**: Text styling utilities + +### Screens (`renamer/screens.py`) +- **OpenScreen**: Directory selection dialog +- **HelpScreen**: Application help and key bindings +- **RenameConfirmScreen**: File rename confirmation dialog + +### Main Components +- **app.py**: Main TUI application +- **main.py**: Entry point +- **constants.py**: Application constants + +## Testing + +Run tests with: +```bash +uv run pytest +``` + +Test files are located in `renamer/test/` with sample filenames in `filenames.txt`. + +## Building and Distribution + +### Build the Package +```bash +uv build +``` + +### Install as Tool +```bash +uv tool install . +``` + +### Uninstall +```bash +uv tool uninstall renamer +``` + +## Code Style + +The project uses standard Python formatting. Consider using tools like: +- `ruff` for linting and formatting +- `mypy` for type checking (if added) + +## Contributing + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Run tests: `uv run pytest` +5. Run the release process: `uv run release` +6. Submit a pull request + +For more information, see the main [README.md](../README.md). \ No newline at end of file diff --git a/README.md b/README.md index 7b3d665..f4993ca 100644 --- a/README.md +++ b/README.md @@ -71,74 +71,9 @@ renamer /path/to/media/directory 4. Press **y** to confirm or **n** to cancel 5. The file will be renamed and the tree updated automatically -## Debugging +## Development -### Formatter Logging -The application includes detailed logging for formatter operations that can be enabled for debugging purposes. - -To enable formatter logging: -```bash -FORMATTER_LOG=1 renamer /path/to/directory -``` - -This will create a `formatter.log` file in the current directory containing: -- Formatter call sequences and ordering -- Input/output values for each formatter -- Caller information (file and line number) -- Any errors during formatting - -Useful for troubleshooting metadata display issues or formatter problems. - -## Architecture - -The application uses a modular architecture with separate extractors and formatters: - -### Extractors -- **MediaInfoExtractor**: Extracts detailed track information using PyMediaInfo -- **FilenameExtractor**: Parses metadata from filenames -- **MetadataExtractor**: Extracts embedded metadata using Mutagen -- **FileInfoExtractor**: Provides basic file information - -### Formatters -- **MediaFormatter**: Formats extracted data for display -- **ProposedNameFormatter**: Generates intelligent rename suggestions -- **TrackFormatter**: Formats video/audio/subtitle track information -- **SizeFormatter**: Formats file sizes -- **DateFormatter**: Formats timestamps -- **DurationFormatter**: Formats time durations -- **ResolutionFormatter**: Formats video resolutions -- **TextFormatter**: Text styling utilities - -### Screens -- **OpenScreen**: Directory selection dialog -- **HelpScreen**: Application help and key bindings -- **RenameConfirmScreen**: File rename confirmation dialog - -### Setup Development Environment -```bash -# Install in development mode -uv sync - -# Run directly (development) -uv run python main.py - -# Or run installed version -renamer -``` - -### Running Without Rebuilding (Development) -```bash -# Run directly from source (no installation needed) -uv run python main.py - -# Or run with specific directory -uv run python main.py /path/to/directory -``` - -### Uninstall -```bash -uv tool uninstall renamer -``` +For development setup, architecture details, debugging information, and contribution guidelines, see [DEVELOP.md](DEVELOP.md). ## Supported Video Formats - .mkv diff --git a/dist/renamer-0.2.5-py3-none-any.whl b/dist/renamer-0.2.5-py3-none-any.whl index b85c9d6e2cb6220a251022102ac85a56762d6aac..a91fa34b31bd3117a04b598d23bc5dff626f0ea8 100644 GIT binary patch delta 7397 zcmZWu1yoeq_Z|k29J;#^Y3VLW32A|$8|m($y9cBZkVYCQNePhYyr(J|9tG*LbX;{6$q+ZDUo5b!bd`{5jj>7lR}0gPc!-%bnRC2MrbLq!KVP zrLPkc(r0k>cb2ncMptvGmqj$*6fX3oq-fHLj|FmEd%Z2ihI^bseO*NdCqHnPhu(nqWn z7vJ)Ia&^EE5@&%(qfCnJAj4WUWqaSehUU_Pr)GV9RKx8;{#hFDWe;Am9>s~O#N(tM zbe=1-_=1ch_XzQ0*jb4zwGI*njROO(bS1t`;04@5qC}g`n_p`l?JYLft*&lv99TOU z=XC^xqu)**7k&Q3K>ztu!mFEGl)LJNukN9}APUe;KfSaP2kF&`ib7cuK(&#!z59nr z+eg#SPd-m!8ILW#l4M}V1=`w<7)Va6B3(~RwDmPVuLY7IzBN#=CYtNv9xxXDa(mLn zM#fmF08#&)wO6P>h_5a8;u7e&WgnTitIss)@rz}qm*Drh7=}pgiR?~xm+>Dfq&T$xEL zZoQe0L9cCH(dF?~Voto3F&t<*)fx{cGwfyNOCe$92?fB(A`6eEP<#+@Cz;LS z(uCr<{U;dOwLVV`i#{^9ngFqY1xSaqZM1I$uay_`16M*e6d%;0~uZp zihN0L6y^r$6)-tCQtC~I%1o!Eb6ajp)|N>JQBqmnHtnIOgb`(F`^vL zRU*vTWQS4>ho*Hg^Fkl1iavULTb}L)3;I|)AN;Il=~=#cd?S414G^oQ#h9rwnNt)} zaAs06bKyH=wHS4?&7lHdn!c&C5>%9XX@|K^Fr=*HM2#@#(^Ea7XzT$FqaV1!S`e@B zD8SVPRE8z#`<3u1Yc&rL>$!j+P9m?|c%OBW@LvC?xeSt(P!4pX&^xmTEnV#!j8u;| z+&Be%ogCGMjF-BPrJeB2#k^&XTvn*e+YIHZIhVZ+`E1iDvabdsUo9-*UhW?H&^amU zdq@jP@bEP6g{Ov&2}qB2+UsHT3qzoO)dW+M{2|ZMZ3~*fVi8}tFc}kEdOn74g?yuU zVrgSUQx?cEoeOleRnD{d7f4U-?(;W4vMQ*X-Qm{hy;Nbvv|Pu>xaXQzfF zHLAqPLRdXtn4z&X&=k(qqT)7vqxS&QaPHRz{s70_ zC;{i#?_Pd5v5r`@B>ktqx^f^x*n^}Coq~in*m4miu`bI6mAGVm=jQxS9p&9q4?hZ> z%W0DI8(*S0@)s);bm&rb8Ae>?r%=F+8A52^%`Yi zAk2{em}QYS0Lfx`dXaAQ-2|cFRiKJo@tje+r%M`-f6@8UQN^KPNQ0l$=)~twx z*#cDYcbQnW??9xfd(1PAfF3@^)wpB7 zb>;d!UX^f(JEINP@(v@22c9FIEZf_xmnX|pWEz~sv7d@!t|$Aj6>*^_T%nZYj_1Au z<6z@6O!Be2no%!FBkr36Wb%Z@*7G??-M(DrenI9iCn;I~y_(7Pw$raslHjnc0FM1! z0&`PgVv-bk8?ngX!h7#}(w-1{jMK4Ma=LpXQpBZUqZ5Le(hEn3+RmEl_(+ESN%)=# zjzXk2v*%)boPQAAr!#rqZ;HcZM~jKTiwVVZv)u$Wei>$_Ku%tqQ#yJNdZYYik(T~7 z!tZ!%#5t8M?UEugWJ8#n^zrmg^WM52m`U$`J`LJ!dk)yaLj>E>N3v^@sS`;>Vt^&|b(s}cm9#PG2d3j^mK|AKQdA7{ z&hLFcZXH^iX*FxnV4o%I^(o_m*#xppIe9W1N})*V7j-31DS2jx@-_PORoP|8o0~NI zU%aEk@9DBHVX=HEvWkI~;H=lcB2|;oJ>2?}2s%f^=XNZD_+-T3W&%ITrS34c!JcgI8;(5AR<{IR4pLpFI! z|AE2fs`pM{NcQ=g!DCYBdo9*cPC;2&kplUTDi}<>rI!+0knt>2#yJhq*jS;vV49`m z)veYOapx+fM{6i+*G~VcDquy0)H8KbBm@9}2?zjS!>S!uOGi@&OIJ=a4+m!sXPkG~t~e*dv;Tl@qWQfeVf^|YW&`sO+!D9EAmYIXK-#2ftfQDxlP z>JgA74wOfSvuVdwhd@2D;+@`x+%?VY0{x`LaF=FZz~yT?_x@d*-;*9Pfzn!~mxL`YkUDV5 z2J@x3J2(o|gqc_UyX`#%*1@%KR(z&!iutChkU7&?)1SQM$TZ=cZ&YE@uPxwthUwff96$uWJ>D05JU4NvXe!4t| z|1QK}DO2hLMR7Dxpz9(7?Mb291ZNO<$!K+LMF)Z<(h!zNyniLq)zaS5)Xfr>%Xsx3 z)m|>ljssR@p~f^hhH7XFri*+x$VCC#jLWV(&!DBme z*W_89ZB<==B(*_>@b(cro5~cTFw+o2!Hs|i&+1~p9CIZS0FXll08j&<2wsE`OK*2q zQ*(DGS6E8lzf?&q;>YPYuX)T(tiL;gZ4)h%YN0E{5R z=WkA)rT4nme>QOJv;rJnuKb%k^_iiYCxRzy>xvN5Z#aTrg`^Fn5>U&HfcyXIcNEg!^!Okgfx8LUTT zq<7=?4r09_c0}Q=HzWP!MY)aEX4;Zm-SpjPCxluU%k*77jSnN9=$9e|+7;O$g0=84OiCq1 zS7f(~>5d}&t}K_~w=v~lh@Z8neMwfl^O1$hF7tk`OHh8Dcs1HN3U(33;9Al*!$g`d zYX#@gTL-C8i7_5}ju+oZej&2W8X7bgZ-Caw=5Ldb_gWQpN*rs@W@dlMvSs9<8M2LJ zZ?7p%=%faV$t-EN9^s6y1R*bkkRzpu*0>kUO<^E@=hNRb#n7nUfkY-2YKCqa5ccQ= z$y8b2hK!IyEO}Kq4N43@wGP|}jcZI-*4S}Z8duLxchVkIptk_P<1!Vghl0%g!%h7b zgCBMuizB&Tm?AX0^B#V~*~1umJ(G~2;Mk2l~}!9L6H-m2brLYs3*Xo~*niTupwQ_LMZQt_z}%=P^6 zn~34i=W=RoaszC3QUk2dSrYli(jE5BqrBs@7?))Z-X74{JZrz}KQfi7Z_D89Jt(jp z>ZnlQG`}5Mx*nLq&{k2~#ps}xdg5a99buFD0y}UExj)hW_7!Bj6g^~_N88~;Y>7wW zvg-^l%5pKsdxo(CkFk*j*IJ;!R2$znyt;RbP8L7$Z-fSd@*%ofyH$ZfafB>otUu=+ zJPv?fyuBBAovw}1Xjx@9;%5AY@kCZb+oqDe=#|zdBLp3vogs~)aZQPtd2V;ugez2q zW!xVq>w2zi_v0Wmd%$Z#$_pw%-8D~Lx@Zl$eR2^{q&4DgdkTeDx1?Xv$`VFE2=y>t z=qz8ja?5V__!LI3Y+2!Xu@Jeiq?9~CoV8lZ-F|xho23XFbWxD^SOY^yg%ZI4qm4x* zx{C=mZ~9b@8>cMx51|P8@n4C|7h#`{LiEtRu?xI?(^?>2>;fktwhWlZJx7bP+$u8; ztD#?0UW+}ARWl4Gt0D8%s`2~QZ?ZguxW4YGh}KTI0?G&rscge?=lyOu*>{Vv0TQmR zl7@O~2cMAol_PC(XR(V}z4<82UFuUOz~-xZoHyX%;T=sKnC*UW)nMEuU(T8%_r@`n zKfE0OC1H&6hUCeiN%@_g`e@o=#kQO5Jg4l0)f+T-cE5f3TpK!4$5ah_yZ4-h6f*R1$iXkr%Hp5pgbIheiVKI z9}v@d>`z%y8Hv3R8#I@ zY^v@3VCQxF;W)HVj~_1kt|$ILBQq#^u-#yJBsh*{TJSJ_XBPEf`7Mf3;IhS6X(0GR zI`8?TT6x%!=Lm(^OGzm`8D$@5f6o5o%gC5!t@h);UYkrHq8V&3S#7!y7H<|Y5tY(? zmXbA@Fp*-gP2zfn^~YfVUA2FX3->!ZV|-Nc2mn9>0RU9cLwj(QdA`S`V)pDSLLN=Sc=vhu_h$Hu#Q*@onE@ zhO~eFL~}7+HJ%hsqIesrYCH1z$(<+0&1tcP#wL~##Y|NG^mQBF)*yK2m% z@yAvRuk$C0s>bP+rqh0Y{7`j_t}2H^lQVwZG;H64OsBY>?bA5Q6)`I4|MCm1ZilqW zeD5yFUVx5h!?d?JGo|D%M-Q{>aJ9TdS3Gf4zVj}5WpDeXGbAQ6*fRwgMJgl$WsajDUp=dwq1R^Hy%*r5<{ypHMG z(Z=sF{at-<#Ec3xO8V|~ggmz7aVtMKU>lo5bxU*{Whb~5TWQ%uSmvc%-vS*54?Sh{D17Xg*Yj-`E;+cCwz ztqbeCC=$o1@aspx&YEij^fNiPGT7N8h5FlSG=gkmv8K#^B64@B8WQUl5z2E`zf8g!|&aGyLOjM{>OMH!i(kx_Y6ouq^5@ z_Q|^WWZx$^5&H!PaZ#rcm9X<9>AuPf0UQ^gS38LK`hD@!=Nj{E#;fJs! zaw~ozA^SKgeaJ&UWfrtJloNZJtl~(8U&Sq8Cnbn7{(ueVJ$d!S#AUFkHBJ)*+HB36cb}0)) z#@qzdo|2t!Ajop=A-V{@`|y-ylr@?$;lGM&TC?bD+TDcY zl1RwS(Nh8-LE4#}h|;xfXSw1LKQHdZ_w9&nqc#ecSeE$4b_JI?^Tba-?sn9BH?#<= zrAxnXyFaTI4IA)6ycvG?fj`+KCtat4l`6{XB`)D}e0H*8NkPB1m!yZJgC)Z?%{AF0 z=RlKn;u^$qLNHc;D59B-_4< z+QKx~FOmn2XFU6qvWF+>WcCMVcKL+;uDA8VxRXw1epb00ZI>I9DfYbt3U2yj)D8+tDMKo)sD<~s`XVHZtOLDc&78K#y&+qEEJ8A^|(?(r`?Y> z=4Lz5fmqAr(KItv)s`f#31kwa> zO2_>t-alRLe?s2FLQdg9DLrW56@!Ea1#prS-o`;)J&55*EDXUVdq8R^2%v$Um=9C? zv+w&mCIC~{qHIY4*iQLB!UZd^8G7Ds%wj}9E`Y%{NETA;tyU;LA^f5>~)p@%+#a2cyF>_*dikQw<>!jS+N5~cls)cP_$IAVMLU0V?5NFMXQDI3>? zx@a@~JqH#)3ZRlc3?YIV`aL-FhatFNXqMk!Gjj8%Oh<>M6A9*wCmus05W?!C7;blm@8?@pe7cm(Az{6+nzEdJMW8-qLGA{yvoASxCUfC*5K0RX)9gfspRzf9Oq delta 6551 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 S0RanqSs&m601Z9}#(x12C2G3> diff --git a/pyproject.toml b/pyproject.toml index a9fb251..b0082d8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,8 @@ dependencies = [ [project.scripts] renamer = "renamer.main:main" +bump-version = "renamer.bump:main" +release = "renamer.release:main" [tool.uv] package = true diff --git a/renamer/__init__.py b/renamer/__init__.py index c843dd0..741abc4 100644 --- a/renamer/__init__.py +++ b/renamer/__init__.py @@ -1,7 +1,7 @@ # Renamer package from .app import RenamerApp -from .extractor import MediaExtractor +from .extractors.extractor import MediaExtractor from .formatters.media_formatter import MediaFormatter __all__ = ['RenamerApp', 'MediaExtractor', 'MediaFormatter'] \ No newline at end of file diff --git a/renamer/app.py b/renamer/app.py index cc4583d..19a65f5 100644 --- a/renamer/app.py +++ b/renamer/app.py @@ -10,7 +10,7 @@ import os from .constants import MEDIA_TYPES from .screens import OpenScreen, HelpScreen, RenameConfirmScreen -from .extractor import MediaExtractor +from .extractors.extractor import MediaExtractor from .formatters.media_formatter import MediaFormatter from .formatters.proposed_name_formatter import ProposedNameFormatter from .formatters.text_formatter import TextFormatter diff --git a/renamer/bump.py b/renamer/bump.py new file mode 100644 index 0000000..6e01da2 --- /dev/null +++ b/renamer/bump.py @@ -0,0 +1,15 @@ +def main(): + import re + with open('pyproject.toml', 'r') as f: + content = f.read() + match = re.search(r'version = "(\d+)\.(\d+)\.(\d+)"', content) + if match: + major, minor, patch = map(int, match.groups()) + patch += 1 + new_version = f'{major}.{minor}.{patch}' + content = content.replace(match.group(0), f'version = "{new_version}"') + with open('pyproject.toml', 'w') as f: + f.write(content) + print(f'Version bumped to {new_version}') + else: + print('Version not found') \ No newline at end of file diff --git a/renamer/extractor.py b/renamer/extractors/extractor.py similarity index 95% rename from renamer/extractor.py rename to renamer/extractors/extractor.py index 4456a72..91a0d03 100644 --- a/renamer/extractor.py +++ b/renamer/extractors/extractor.py @@ -1,9 +1,9 @@ from pathlib import Path -from .extractors.filename_extractor import FilenameExtractor -from .extractors.metadata_extractor import MetadataExtractor -from .extractors.mediainfo_extractor import MediaInfoExtractor -from .extractors.fileinfo_extractor import FileInfoExtractor -from .extractors.default_extractor import DefaultExtractor +from .filename_extractor import FilenameExtractor +from .metadata_extractor import MetadataExtractor +from .mediainfo_extractor import MediaInfoExtractor +from .fileinfo_extractor import FileInfoExtractor +from .default_extractor import DefaultExtractor class MediaExtractor: diff --git a/renamer/release.py b/renamer/release.py new file mode 100644 index 0000000..4954f57 --- /dev/null +++ b/renamer/release.py @@ -0,0 +1,22 @@ +def main(): + import subprocess + import sys + + try: + # Bump version + print("Bumping version...") + subprocess.run([sys.executable, '-m', 'renamer.bump'], check=True) + + # Sync dependencies + print("Syncing dependencies...") + subprocess.run(['uv', 'sync'], check=True) + + # Build package + print("Building package...") + subprocess.run(['uv', 'build'], check=True) + + print("Release process completed successfully!") + + except subprocess.CalledProcessError as e: + print(f"Error during release process: {e}") + sys.exit(1) \ No newline at end of file