Compare commits
10
Commits
80de4ff1fd
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0490ff7265 | ||
|
|
4fa4bcd445 | ||
|
|
4ac6dda7e1 | ||
|
|
3c7ff0e040 | ||
|
|
b6a6fb1962 | ||
|
|
4e35dfa4f1 | ||
|
|
e4cfd54a13 | ||
|
|
910b4cee66 | ||
|
|
c235a9e8b5 | ||
|
|
2f303fc984 |
@@ -0,0 +1,5 @@
|
||||
# Local settings for the Obsidian sync script
|
||||
scripts/.env
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
@@ -16,7 +16,7 @@
|
||||
| EYEBROWS | 03 |
|
||||
| EYEBROW COLOR | 06 (BLACK) |
|
||||
| EYELASH COLOR | 25 (BLACK) |
|
||||
| NOSE | 05 |
|
||||
| NOSE | 02 |
|
||||
| MOUTH | 13 |
|
||||
| JAW | 06 |
|
||||
| EARS | 03 |
|
||||
|
||||
@@ -7,6 +7,7 @@ Setup for weather, lighting and color grading. All mods in this guide are by **C
|
||||
- **The Nullifier** removes area-specific lighting overrides, so the custom weather also shows up everywhere (e.g. in the Badlands).
|
||||
- **Nova LUT 4** is the color grading (LUT). **LUT Switcher 3** lets you switch LUTs in game.
|
||||
- **Nova Optics** fine-tunes exposure. Use it if Nova City 2 is too dark for you.
|
||||
- **Torrent** replaces the flat vanilla rain with real drops lit by the city, and adds storms with lightning and thunder.
|
||||
|
||||
> Nova City 2 is designed for **Path Tracing**. It still works with RT or raster, but those modes are not its focus.
|
||||
|
||||
@@ -14,18 +15,21 @@ Setup for weather, lighting and color grading. All mods in this guide are by **C
|
||||
|
||||
## Mods
|
||||
|
||||
| Mod name | Link | Purpose | Note |
|
||||
| ---------------- | --------------------------------------------------------------- | ---------------------------------------------- | ------------------------------------------ |
|
||||
| Nova City 2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12490) | Weather & lighting overhaul (ENV) | |
|
||||
| Weather Switcher | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18027) | Change weather, control time, customize clouds | **Required** by Nova City 2 |
|
||||
| The Nullifier | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/23091) | Removes sector lighting overrides | **Required** by Nova City 2 |
|
||||
| Nova LUT 4.0 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11622) | Color grading (LUT) | |
|
||||
| LUT Switcher 3 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/16310) | Switch LUTs in real time | + Optional file: **"LUT Pack - Nova LUT"** |
|
||||
| Nova Optics | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/29190) | Exposure, bloom, vignette etc. + vehicle fix | Optional, see [Nova Optics](#nova-optics) |
|
||||
| Mod name | Link | Purpose | Note |
|
||||
| ---------------- | --------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------ |
|
||||
| Nova City 2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12490) | Weather & lighting overhaul (ENV) | |
|
||||
| Weather Switcher | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18027) | Change weather, control time, customize clouds | **Required** by Nova City 2 |
|
||||
| The Nullifier | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/23091) | Removes sector lighting overrides | **Required** by Nova City 2 |
|
||||
| Nova LUT 4.0 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11622) | Color grading (LUT) | |
|
||||
| LUT Switcher 3 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/16310) | Switch LUTs in real time | + Optional file: **"LUT Pack - Nova LUT"** |
|
||||
| Nova Optics | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/29190) | Exposure, bloom, vignette etc. + vehicle fix | Optional, see [Nova Optics](#nova-optics) |
|
||||
| Torrent | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/37031) | Realistic rain, storm mist, lightning & thunder | Optional, see [Torrent](#torrent) |
|
||||
|
||||
**Requirements** (all listed under _Dependency Mods_ in [SitirioTV's Cyberpunk 2077 Mod Collection](./SitirioTVs-Cyberpunk-2077-Mod-Collection.md)):
|
||||
[Cyber Engine Tweaks](./cyber-engine-tweaks.md), Codeware, redscript, RED4ext, ArchiveXL, TweakXL, Window Utils
|
||||
|
||||
For **Torrent** also: Mod Settings (to change its settings) and AudioXL (optional, without it the lightning has no thunder)
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
@@ -34,6 +38,7 @@ Setup for weather, lighting and color grading. All mods in this guide are by **C
|
||||
2. Drag & drop the content of each ZIP into the Cyberpunk 2077 root folder.
|
||||
- Steam: `...\steamapps\common\Cyberpunk 2077\`
|
||||
3. For **LUT Switcher 3**, also download the optional file **"LUT Pack - Nova LUT"** from its _Files_ tab. Without a pack, LUT Switcher shows no LUTs.
|
||||
4. For **Torrent**, keep the regular **Nova City 2** main file. You do **not** need _"Nova City 2 - No Custom Rain"_: that version is meant for other rain mods, while Torrent builds on Nova City 2's rain weathers and replaces the rain itself.
|
||||
|
||||
> **Updating from Nova City 1?** Delete the `NovaCityTools` folder in `bin\x64\plugins\cyber_engine_tweaks\mods\` and the `NovaOverrides.ini` config file.
|
||||
|
||||
@@ -53,7 +58,7 @@ Setup for weather, lighting and color grading. All mods in this guide are by **C
|
||||
|
||||
## Setup in Game
|
||||
|
||||
All three tools are configured in the **CET overlay** (see [Cyber Engine Tweaks](./cyber-engine-tweaks.md)). Each one has its own window.
|
||||
LUT Switcher, Weather Switcher and Nova Optics are configured in the **CET overlay** (see [Cyber Engine Tweaks](./cyber-engine-tweaks.md)). Each one has its own window. Torrent uses the **Mod Settings** menu instead.
|
||||
|
||||
### LUT Switcher
|
||||
|
||||
@@ -103,18 +108,46 @@ Changes are applied live and saved when you release the slider.
|
||||
|
||||
> Higher values brighten dark scenes further, but the image can start to look washed out. Check the result at night **and** at noon.
|
||||
|
||||
### Torrent
|
||||
|
||||
> **Warning:** Storms bring lightning flashes. If flashing lights bother you, turn on **Reduce Flashes** or set **Lightning** to **Off**.
|
||||
|
||||
No setup needed, the defaults work fine. All settings are under **Mod Settings > Torrent**:
|
||||
|
||||
| Setting | What it does |
|
||||
| -------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| Enabled / Quality | Turns the mod on or off. Quality: Low, Medium, High or Ultra |
|
||||
| Intensity | More and thicker rain on top of each weather's look |
|
||||
| Visibility | Use it if the rain looks too faint on your setup |
|
||||
| Rain Cover | How rain gets under roofs and bridges: **Simple** (straight down), **Auto** (default, only when windy), **Full** |
|
||||
| Storm Mist | Wind-blown mist and spray in Nova City 2's _Storm_ weather |
|
||||
| Lightning | **Off**, **Storms Only** or **All Rain** |
|
||||
| Lightning Frequency | 1 to 10 (default 3). Each step means about 50 % more strikes |
|
||||
| Reduce Flashes | Dimmer bolts, one slow glow instead of a flicker, fewer strikes |
|
||||
| Thunder Volume | Needs AudioXL |
|
||||
| Lightning Strike Key | Key to trigger a strike on demand while it's raining |
|
||||
|
||||
> Use **Weather Switcher** to set a rain or storm state for testing. Lightning comes mostly between 9 pm and 2 am game time.
|
||||
|
||||
The performance cost is small: about 1-2 FPS with the default settings. Torrent saves nothing to your save game, so you can install or remove it at any time.
|
||||
|
||||
**Uninstall:** Delete the folders `red4ext\plugins\Torrent` and `red4ext\plugins\AudioXL\sounds\Torrent`.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | Solution |
|
||||
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
|
||||
| Still too dark | Raise **Shadow Boost** in Nova Optics. Reset the in-game gamma to default. A flashlight mod helps in unlit areas |
|
||||
| Nova Optics doesn't change anything | Check that it says **Enabled**, **Auto** is unchecked and **Override** + **Global** are checked |
|
||||
| Badlands / some areas ignore the weather | **The Nullifier** is missing |
|
||||
| Weather never changes | Turn off **Auto Apply** in Weather Switcher, or click **Reset/Resume Weather** |
|
||||
| LUT Switcher shows no LUTs | Install the optional **"LUT Pack - Nova LUT"** |
|
||||
| LUT Switcher / Nova Optics window missing | CET or one of the requirements is missing or outdated |
|
||||
| Problem | Solution |
|
||||
| ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| Still too dark | Raise **Shadow Boost** in Nova Optics. Reset the in-game gamma to default. A flashlight mod helps in unlit areas |
|
||||
| Nova Optics doesn't change anything | Check that it says **Enabled**, **Auto** is unchecked and **Override** + **Global** are checked |
|
||||
| Badlands / some areas ignore the weather | **The Nullifier** is missing |
|
||||
| Weather never changes | Turn off **Auto Apply** in Weather Switcher, or click **Reset/Resume Weather** |
|
||||
| LUT Switcher shows no LUTs | Install the optional **"LUT Pack - Nova LUT"** |
|
||||
| LUT Switcher / Nova Optics window missing | CET or one of the requirements is missing or outdated |
|
||||
| Lightning has no thunder | **AudioXL** is missing, or **Thunder Volume** in Torrent's settings is too low |
|
||||
| Rain looks flat again after a game update | Torrent stops drawing when a patch changes the game's rain, until Torrent is updated |
|
||||
| Lower FPS in rain | In Torrent's settings: lower **Quality** to High or Medium, set **Rain Cover** to Simple, or turn off **Storm Mist** |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Mod List (v2.5)
|
||||
|
||||
> _Last Update: 09th November 2026_
|
||||
> _Last Update: 11th November 2026_
|
||||
|
||||
### Dependency Mods
|
||||
|
||||
@@ -21,64 +21,68 @@
|
||||
| Window Utils | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/26589) | YES |
|
||||
| Deceptious Quest Core | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/7831) | YES |
|
||||
| Deceptious Quest Core Utilities and Settings | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/24404) | YES |
|
||||
| AudioXL | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/33442) | YES |
|
||||
|
||||
---
|
||||
|
||||
### Content Mods
|
||||
|
||||
| Mod name | Link | Category | Note | Up-to-date |
|
||||
| ---------------------------------------------------------- | --------------------------------------------------------------- | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| Photo Mode Unlocker 2.3 XL | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4319) | Character | | YES |
|
||||
| Preem Hair | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8223) | Character / Visual | | YES |
|
||||
| Preem Skin | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8157) | Character / Visual | | YES |
|
||||
| Panam Body Enhanced 2.2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4843) | Character / Visual | <span style="color:red">Rename the two .archive files of the **Panam Romance Mod** with " **z\_ "** ("z_PanamPrivacy.archive" & "z_PanamRomancedEnhanced.archive")</span> | YES |
|
||||
| Judy Enhanced Body with 4K Texture | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10150) | Character / Visual | + Optional | YES |
|
||||
| Better Netrunning - Hacking Reworked | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2302) | Gameplay | <span style="color:red">Changes the rules of Netrunning / Hacking.</span> Please read the Mod description beforehand. | YES |
|
||||
| Custom Blackwall quickhacks | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9759) | Gameplay / Ability | | YES |
|
||||
| Cyberware-EX | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9429) | Gameplay / Ability | | YES |
|
||||
| Better Sleeves | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10319) | Immersion | | YES |
|
||||
| Hackable and Grabbable Civilians | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18847) | Immersion | | <span style="color:red">NOT YET</span> |
|
||||
| Lean Anywhere | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9938) | Immersion | | YES |
|
||||
| Sit Anywhere | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/7299) | Immersion | | YES |
|
||||
| Trace Position Overhaul | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12445) | Immersion | | YES |
|
||||
| Nova LUT 4.0 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11622) | Lighting / Visual | | YES |
|
||||
| LUT Switcher 3 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/16310) | Lighting / Visual | + Optional: "LUT Pack - Nova LUT" | YES |
|
||||
| Weather Switcher | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18027) | Lighting / Visual | [The Nullifier](https://www.nexusmods.com/cyberpunk2077/mods/23091) REQUIRED to avoid sector lighting overrides (like Badlands not having custom weather) | YES |
|
||||
| Underwear remover rebuilt | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18538) | NSFW | | YES |
|
||||
| Cyber Drift | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8306) | QoL | Car Physics | YES |
|
||||
| Dynamic Downforce | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12841) | QoL | Car Physics | YES |
|
||||
| Dynamic Gravity Modifier | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/13986) | QoL | Car Physics | YES |
|
||||
| Gripped up | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12937) | QoL | Car Physics | YES |
|
||||
| Real Vendor Names | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4941) | QoL | | YES |
|
||||
| The Passenger - Feature Settings | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18380) | QoL | | YES |
|
||||
| Realistic Map | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/17811) | QoL | 16K Version | YES |
|
||||
| Aurore Romanced (Lady Marmalade) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11097) | Romance | | YES |
|
||||
| Hangout Romances | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18972) | Romance | | YES |
|
||||
| I Really Want To Stay At Your House - Judy | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8753) | Romance | | YES |
|
||||
| I Really Want To Stay At Your House - Panam | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8775) | Romance | | YES |
|
||||
| Judy Romanced Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4508) | Romance | | YES |
|
||||
| Panam Romance for female V | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2782) | Romance | Use command below + <span style="color:red">Might break Male V Romance with Panam</span> | YES |
|
||||
| Panam Romanced Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4626) | Romance | | YES |
|
||||
| Romance Hangouts Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11590) | Romance | | YES |
|
||||
| Non-Canon Romances Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/20466) | Romance | | YES |
|
||||
| Romanced Enhanced Showers Feature | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/23074) | Romance | | YES |
|
||||
| AMM - Appearance Menu Mod | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/790) | Scripting | | YES |
|
||||
| [Cyber Engine Tweaks](./cyber-engine-tweaks.md) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/107) | Scripting | | YES |
|
||||
| FreeFly (Noclip) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/780) | Scripting | | YES |
|
||||
| Ultimate AMM Locations Collection (over 700) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11996) | Scripting | Extension for _Appearance Menu Mod_ + See description for location guide | YES |
|
||||
| Immersive First Person | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2675) | Visual | | YES |
|
||||
| RELENTLESS-Live Dismemberment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/35703) | Visual | | YES |
|
||||
| GoreRunner (Blood and Carnage Overhaul) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/24210) | Visual | | YES |
|
||||
| Collateral Damage - Civilian Dismemberment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/36454) | Visual | | YES |
|
||||
| Nova City 2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12490) | Visual | + Recommended: Use [Nova Optics](https://www.nexusmods.com/cyberpunk2077/mods/29190) and set Exposure Override (Global) to 2.50 | YES |
|
||||
| Nova Optics | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/29190) | Visual | Switch the mod to **Enabled**, disable **Auto**. Under **Exposure**: enable **Override** + **Global**, set **Shadow Boost** to **2.50** (if [Nova City 2](https://www.nexusmods.com/cyberpunk2077/mods/12490) is too dark) | YES |
|
||||
| Better traffic lights | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/14316) | World | | YES |
|
||||
| V's Edgerunners Mansion - Apartment DLC | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/5437) | World | | YES |
|
||||
| A New Dawn Beyond Night City | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/15524) | World | | YES |
|
||||
| Game World Boundary Removed | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/20876) | World | | YES |
|
||||
| Luxury corporate the Glen apartment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18670) | World | | YES |
|
||||
| Eden Plaza - Charter Hill Player Penthouse (World Builder) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/25409) | World | | YES |
|
||||
| NIGHT CITY ALIVE | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10395) | World / Immersion | | <span style="color:orange">LITE, FULL COMES LATER</span> |
|
||||
| Mod name | Link | Category | Note | Up-to-date |
|
||||
| ---------------------------------------------------------- | --------------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
|
||||
| Photo Mode Unlocker 2.3 XL | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4319) | Character | | YES |
|
||||
| Preem Hair | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8223) | Character / Visual | | YES |
|
||||
| Preem Skin | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8157) | Character / Visual | | YES |
|
||||
| Panam Body Enhanced 2.2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4843) | Character / Visual | <span style="color:red">Rename the two .archive files of the **Panam Romance Mod** with " **z\_ "** ("z_PanamPrivacy.archive" & "z_PanamRomancedEnhanced.archive")</span> | YES |
|
||||
| Judy Enhanced Body with 4K Texture | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10150) | Character / Visual | + Optional | YES |
|
||||
| Better Netrunning - Hacking Reworked | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2302) | Gameplay | <span style="color:red">Changes the rules of Netrunning / Hacking.</span> Please read the Mod description beforehand. | YES |
|
||||
| Custom Blackwall quickhacks | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9759) | Gameplay / Ability | | YES |
|
||||
| Cyberware-EX | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9429) | Gameplay / Ability | | YES |
|
||||
| Better Sleeves | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10319) | Immersion | | YES |
|
||||
| Hackable and Grabbable Civilians | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18847) | Immersion | | <span style="color:red">NOT YET</span> |
|
||||
| Lean Anywhere | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9938) | Immersion | | YES |
|
||||
| Sit Anywhere | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/7299) | Immersion | | YES |
|
||||
| Trace Position Overhaul | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12445) | Immersion | | YES |
|
||||
| Nova LUT 4.0 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11622) | Lighting / Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| LUT Switcher 3 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/16310) | Lighting / Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| Weather Switcher | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18027) | Lighting / Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| Cyber Drift | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8306) | QoL | Car Physics | YES |
|
||||
| Dynamic Downforce | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12841) | QoL | Car Physics | YES |
|
||||
| Dynamic Gravity Modifier | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/13986) | QoL | Car Physics | YES |
|
||||
| Gripped up | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12937) | QoL | Car Physics | YES |
|
||||
| Real Vendor Names | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4941) | QoL | | YES |
|
||||
| The Passenger - Feature Settings | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18380) | QoL | | YES |
|
||||
| Realistic Map | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/17811) | QoL | 16K Version | YES |
|
||||
| Aurore Romanced (Lady Marmalade) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11097) | Romance | | YES |
|
||||
| Hangout Romances | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18972) | Romance | | YES |
|
||||
| I Really Want To Stay At Your House - Judy | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8753) | Romance | | YES |
|
||||
| I Really Want To Stay At Your House - Panam | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/8775) | Romance | | YES |
|
||||
| Judy Romanced Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4508) | Romance | | YES |
|
||||
| Panam Romance for female V | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2782) | Romance | Use command below + <span style="color:red">Might break Male V Romance with Panam</span> | YES |
|
||||
| Panam Romanced Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/4626) | Romance | | YES |
|
||||
| Romance Hangouts Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11590) | Romance | | YES |
|
||||
| Non-Canon Romances Enhanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/20466) | Romance | | YES |
|
||||
| Romanced Enhanced Showers Feature | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/23074) | Romance | | YES |
|
||||
| Rita Wheeler Romanced | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/9191) | Romance | | YES |
|
||||
| Underwear remover rebuilt | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18538) | Scripting | | YES |
|
||||
| AMM - Appearance Menu Mod | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/790) | Scripting | | YES |
|
||||
| [Cyber Engine Tweaks](./cyber-engine-tweaks.md) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/107) | Scripting | | YES |
|
||||
| FreeFly (Noclip) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/780) | Scripting | | YES |
|
||||
| Ultimate AMM Locations Collection (over 700) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/11996) | Scripting | Extension for _Appearance Menu Mod_ + See description for location guide | YES |
|
||||
| Forbidden Vehicle Movement No More | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/15757) | Scripting | | YES |
|
||||
| Immersive First Person | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/2675) | Visual | | YES |
|
||||
| RELENTLESS-Live Dismemberment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/35703) | Visual | | YES |
|
||||
| GoreRunner (Blood and Carnage Overhaul) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/24210) | Visual | | YES |
|
||||
| Collateral Damage - Civilian Dismemberment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/36454) | Visual | | YES |
|
||||
| Nova City 2 | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/12490) | Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| Nova Optics | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/29190) | Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| Torrent | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/37031) | Visual | See [Lighting and Visuals Setup](./Lighting-and-Visuals-Setup.md) | YES |
|
||||
| Better traffic lights | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/14316) | World | | YES |
|
||||
| V's Edgerunners Mansion - Apartment DLC | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/5437) | World | | YES |
|
||||
| A New Dawn Beyond Night City | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/15524) | World | | YES |
|
||||
| Game World Boundary Removed | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/20876) | World | | YES |
|
||||
| Luxury corporate the Glen apartment | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/18670) | World | | YES |
|
||||
| Eden Plaza - Charter Hill Player Penthouse (World Builder) | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/25409) | World | | YES |
|
||||
| NIGHT CITY ALIVE | [NexusMods](https://www.nexusmods.com/cyberpunk2077/mods/10395) | World / Immersion | | <span style="color:orange">LITE, FULL COMES LATER</span> |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
|
||||
## Weapons
|
||||
|
||||
| WEAPON | HOW TO GET |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| YINGLONG (ICONIC) | [Location - YouTube](https://www.youtube.com/watch?v=TdfHuOcBumw) |
|
||||
| LEXINGTON X-MOD2 (ICONIC) | Win the game at the gun shop in Megabuilding H10 |
|
||||
| BYAKKO (ICONIC) | You can get the Byakko Katana during Wakako's questline in Cyberpunk 2077. The Katana cannot be purchased from a vendor, so you will need to complete the "Professional Widow" side gig to get your hands on the Byakko Katana. |
|
||||
| NUE (TIER 5) | Mods: Kanetsugu, XC-10, 2x Swiss Cheese |
|
||||
| SIHIL | ARIADNE chat |
|
||||
| WEAPON | HOW TO GET |
|
||||
| ------------------------- | ----------------------------------------------------------------- |
|
||||
| YINGLONG (ICONIC) | [Location - YouTube](https://www.youtube.com/watch?v=TdfHuOcBumw) |
|
||||
| LEXINGTON X-MOD2 (ICONIC) | Win the game at the gun shop in Megabuilding H10 |
|
||||
| SIHIL (ICONIC) | ARIADNE chat |
|
||||
| NUE (TIER 5) | Mods: Kanetsugu, XC-10, 2x Swiss Cheese |
|
||||
|
||||
---
|
||||
|
||||
@@ -45,12 +44,12 @@
|
||||
### Integumentary System
|
||||
|
||||
- CARAPACE
|
||||
- SHOCK-N-AWE
|
||||
- CHITIN (ICONIC)
|
||||
- COGITO LATTICE
|
||||
|
||||
### Operating System
|
||||
|
||||
- TETRATONIC RIPPLER MK. 5 (in order)
|
||||
- TETRATRONIC RIPPLER MK. 5 (in order)
|
||||
- MEMORY WIPE
|
||||
- SONIC SHOCK
|
||||
- OVERHEAT
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 380 KiB After Width: | Height: | Size: 4.1 MiB |
@@ -0,0 +1,12 @@
|
||||
# Copy this file to .env (same folder) and adjust the values.
|
||||
# .env is git-ignored and stays on your machine.
|
||||
|
||||
# Absolute path to your Obsidian vault
|
||||
OBSIDIAN_VAULT=C:\Users\<user>\path\to\Your Vault
|
||||
|
||||
# Vault folders that contain images, relative to the vault. Separate multiple with ";"
|
||||
OBSIDIAN_IMAGE_DIRS=03_Resources/Hobby
|
||||
|
||||
# Headings of sections that are not published (whole section incl. subheadings).
|
||||
# Case-insensitive, HTML tags ignored. Separate multiple with ";". Leave empty for none.
|
||||
OBSIDIAN_EXCLUDE_SECTIONS=Exclude This Section;Separated by Semicolon
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"repo": "",
|
||||
"assets_dir": "assets",
|
||||
"default_image_width": 400,
|
||||
"formatter": ["npx", "--yes", "prettier@3.3.3"],
|
||||
|
||||
"notes": [
|
||||
{
|
||||
"source": "00_MOCs/Cyberpunk MOC.md",
|
||||
"target": "README.md",
|
||||
"title": "Cyberpunk 2077 Guide"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Panam Romance Guide.md",
|
||||
"target": "Panam-Romance-Guide.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Judy Romance Guide.md",
|
||||
"target": "Judy-Romance-Guide.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Female V Appearance.md",
|
||||
"target": "Female-V-Appearance.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Ultimate Netrunner Build.md",
|
||||
"target": "Ultimate-Netrunner-Build.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Unlock Secret Ending Dialogue Options.md",
|
||||
"target": "Unlock-Secret-Ending-Dialogue-Options.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/SitirioTV's Cyberpunk 2077 Mod Collection.md",
|
||||
"target": "SitirioTVs-Cyberpunk-2077-Mod-Collection.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Lighting and Visuals Setup.md",
|
||||
"target": "Lighting-and-Visuals-Setup.md"
|
||||
},
|
||||
{
|
||||
"source": "02_Areas/Hobby/Cyber Engine Tweaks.md",
|
||||
"target": "cyber-engine-tweaks.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,324 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Sync Cyberpunk notes from the Obsidian vault into the Git repo.
|
||||
|
||||
Conversions (Obsidian -> repo):
|
||||
- Removes YAML front matter and back-links like "> [[Home]]"
|
||||
- Removes private sections (by heading, or between %% private-start %% / %% private-end %%)
|
||||
- [[Note]] / [[Note|Alias]] / [[Note#Heading]] -> [Note](./Repo-File.md#heading)
|
||||
- [[#Heading]] -> [Heading](#heading)
|
||||
- ![[image.jpg]] / ![[image.jpg|800]] -> <img src="./assets/image.jpg" alt="image" width="...">
|
||||
- Copies referenced images from the vault into assets/ (only if new or changed)
|
||||
- ==highlight== -> plain text (not supported outside Obsidian)
|
||||
- Cleans heading artifacts ("# # Title", "## > Title"), stray BOMs, trailing "---"
|
||||
- Formats the result with Prettier (same style as format-on-save in VS Code)
|
||||
|
||||
Setup:
|
||||
Copy scripts/.env.example to scripts/.env and set your vault path.
|
||||
scripts/.env is git-ignored; everything else in scripts/ is versioned.
|
||||
|
||||
Usage:
|
||||
python scripts/sync-from-obsidian.py # dry run: shows what would change
|
||||
python scripts/sync-from-obsidian.py -d / --diff # dry run + unified diff
|
||||
python scripts/sync-from-obsidian.py -w / --write # write the files
|
||||
|
||||
Nothing is committed. Review with `git diff`, then commit yourself.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import difflib
|
||||
import filecmp
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SCRIPT_DIR = Path(__file__).resolve().parent
|
||||
CONFIG_PATH = SCRIPT_DIR / "sync-config.json"
|
||||
ENV_PATH = SCRIPT_DIR / ".env"
|
||||
|
||||
WIKILINK_IMAGE = re.compile(r"!\[\[([^\]|]+?\.(?:png|jpe?g|gif|webp|svg))(?:\|(\d+))?\]\]", re.I)
|
||||
WIKILINK = re.compile(r"(?<!!)\[\[([^\]|#]*)(?:#([^\]|]+))?(?:\|([^\]]+))?\]\]")
|
||||
FRONT_MATTER = re.compile(r"\A---\r?\n.*?\r?\n---[ \t]*\r?\n", re.S)
|
||||
HEADING = re.compile(r"^(#{1,6})\s+(.*?)\s*$")
|
||||
HIGHLIGHT = re.compile(r"(?<!`)==(?=\S)([^=\n]+?)(?<=\S)==(?!`)")
|
||||
PRIVATE_START = re.compile(r"^\s*%%\s*private-start\s*%%\s*$", re.I)
|
||||
PRIVATE_END = re.compile(r"^\s*%%\s*private-end\s*%%\s*$", re.I)
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- helpers
|
||||
|
||||
def load_env(path: Path) -> dict[str, str]:
|
||||
"""Minimal .env reader (KEY=value, # comments, optional quotes). Real env vars take precedence."""
|
||||
values: dict[str, str] = {}
|
||||
if path.is_file():
|
||||
for raw in path.read_text(encoding="utf-8-sig").splitlines():
|
||||
line = raw.strip()
|
||||
if not line or line.startswith("#") or "=" not in line:
|
||||
continue
|
||||
key, value = line.split("=", 1)
|
||||
value = value.strip()
|
||||
if len(value) >= 2 and value[0] == value[-1] and value[0] in "\"'":
|
||||
value = value[1:-1]
|
||||
values[key.strip()] = value
|
||||
values.update({k: v for k, v in os.environ.items() if k in values or k.startswith("OBSIDIAN_")})
|
||||
return values
|
||||
|
||||
|
||||
def slugify(text: str) -> str:
|
||||
"""GitHub/Gitea-style heading anchor."""
|
||||
text = re.sub(r"<[^>]+>", "", text).strip().lower()
|
||||
text = re.sub(r"[^\w\- ]", "", text)
|
||||
return text.replace(" ", "-")
|
||||
|
||||
|
||||
def heading_text(raw: str) -> str:
|
||||
"""Heading text without HTML tags, for matching excluded sections."""
|
||||
return re.sub(r"<[^>]+>", "", raw).strip()
|
||||
|
||||
|
||||
def read_text(path: Path) -> str:
|
||||
return path.read_text(encoding="utf-8-sig").replace("\r\n", "\n")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- conversion
|
||||
|
||||
class Converter:
|
||||
def __init__(self, cfg: dict, vault: Path):
|
||||
self.cfg = cfg
|
||||
self.vault = vault
|
||||
self.notes: dict[str, str] = {Path(n["source"]).stem: n["target"] for n in cfg["notes"]}
|
||||
self.default_width = cfg.get("default_image_width", 400)
|
||||
self.excluded = {h.lower() for h in cfg.get("exclude_sections", [])}
|
||||
self.images: set[str] = set()
|
||||
self.warnings: list[str] = []
|
||||
|
||||
def convert(self, text: str, source: str) -> str:
|
||||
text = FRONT_MATTER.sub("", text, count=1)
|
||||
text = text.replace("", "")
|
||||
lines = self._drop_private(text.split("\n"))
|
||||
out, in_code = [], False
|
||||
for l in lines:
|
||||
if l.lstrip().startswith("```"):
|
||||
in_code = not in_code
|
||||
if in_code or l.lstrip().startswith("```"):
|
||||
out.append(l)
|
||||
elif not self._is_backlink(l):
|
||||
out.append(self._line(l, source))
|
||||
return self._tidy(out)
|
||||
|
||||
# -- sections
|
||||
|
||||
def _drop_private(self, lines: list[str]) -> list[str]:
|
||||
out, in_code, skip_marker, skip_level = [], False, False, 0
|
||||
for line in lines:
|
||||
if line.lstrip().startswith("```"):
|
||||
in_code = not in_code
|
||||
if not in_code:
|
||||
if PRIVATE_START.match(line):
|
||||
skip_marker = True
|
||||
continue
|
||||
if PRIVATE_END.match(line):
|
||||
skip_marker = False
|
||||
continue
|
||||
m = HEADING.match(line)
|
||||
if m:
|
||||
level = len(m.group(1))
|
||||
if skip_level and level <= skip_level:
|
||||
skip_level = 0
|
||||
if not skip_level and heading_text(m.group(2)).lower() in self.excluded:
|
||||
skip_level = level
|
||||
if not skip_marker and not skip_level:
|
||||
out.append(line)
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def _is_backlink(line: str) -> bool:
|
||||
return bool(re.fullmatch(r">\s*\[\[[^\]]+\]\]\s*", line.strip()))
|
||||
|
||||
# -- inline
|
||||
|
||||
def _line(self, line: str, source: str) -> str:
|
||||
m = HEADING.match(line)
|
||||
if m: # "# # Title" / "## > Title" -> clean heading
|
||||
title = re.sub(r"^(?:#+\s+|>\s+)", "", m.group(2))
|
||||
line = f"{m.group(1)} {title}"
|
||||
line = HIGHLIGHT.sub(r"\1", line) # ==text== -> text (Gitea has no highlight)
|
||||
line = WIKILINK_IMAGE.sub(self._image, line)
|
||||
return WIKILINK.sub(lambda mm: self._link(mm, source), line)
|
||||
|
||||
def _image(self, m: re.Match) -> str:
|
||||
name, width = m.group(1).strip(), m.group(2) or self.default_width
|
||||
self.images.add(name)
|
||||
return f'<img src="./assets/{name}" alt="{Path(name).stem}" width="{width}">'
|
||||
|
||||
def _link(self, m: re.Match, source: str) -> str:
|
||||
note, anchor, alias = (m.group(1) or "").strip(), m.group(2), m.group(3)
|
||||
label = alias or (note if note else anchor)
|
||||
if not note: # [[#Heading]]
|
||||
return f"[{label}](#{slugify(anchor)})"
|
||||
target = self.notes.get(note)
|
||||
if not target:
|
||||
self.warnings.append(f"{source}: no repo file for [[{note}]], kept as plain text")
|
||||
return label
|
||||
return f"[{label}](./{target}{'#' + slugify(anchor) if anchor else ''})"
|
||||
|
||||
# -- layout
|
||||
|
||||
@staticmethod
|
||||
def _tidy(lines: list[str]) -> str:
|
||||
out: list[str] = []
|
||||
in_code = False
|
||||
for line in lines:
|
||||
line = line.rstrip()
|
||||
if line.startswith("```"):
|
||||
in_code = not in_code
|
||||
elif not in_code:
|
||||
needs_gap = HEADING.match(line) or line == "---"
|
||||
if needs_gap and out and out[-1] != "":
|
||||
out.append("")
|
||||
if out and out[-1] == "" and line == "":
|
||||
continue
|
||||
if out and out[-1] == "---" and line and not HEADING.match(line):
|
||||
out.append("")
|
||||
out.append(line)
|
||||
while out and out[0] in ("", "---"):
|
||||
out.pop(0)
|
||||
while out and out[-1] in ("", "---"):
|
||||
out.pop()
|
||||
return "\n".join(out) + "\n"
|
||||
|
||||
|
||||
class Formatter:
|
||||
"""Runs Prettier on the converted Markdown (via stdin), if configured and available."""
|
||||
|
||||
def __init__(self, cmd: list[str] | None, warnings: list[str]):
|
||||
self.cmd, self.warnings, self.disabled = cmd, warnings, not cmd
|
||||
if cmd:
|
||||
exe = shutil.which(cmd[0]) # resolves npx.cmd on Windows
|
||||
if exe:
|
||||
self.cmd = [exe, *cmd[1:]]
|
||||
else:
|
||||
self.disabled = True
|
||||
warnings.append(f"formatter '{cmd[0]}' not found, output is not formatted")
|
||||
|
||||
def __call__(self, text: str, filename: str) -> str:
|
||||
if self.disabled:
|
||||
return text
|
||||
try:
|
||||
res = subprocess.run([*self.cmd, "--stdin-filepath", filename], input=text,
|
||||
capture_output=True, text=True, encoding="utf-8", timeout=120)
|
||||
except (OSError, subprocess.TimeoutExpired) as e:
|
||||
res = None
|
||||
err = str(e)
|
||||
else:
|
||||
err = res.stderr.strip()
|
||||
if res is None or res.returncode != 0:
|
||||
self.disabled = True
|
||||
self.warnings.append(f"formatter failed ({err[:200]}), output is not formatted")
|
||||
return text
|
||||
return res.stdout.replace("\r\n", "\n")
|
||||
|
||||
|
||||
# --------------------------------------------------------------------------- main
|
||||
|
||||
def find_image(vault: Path, dirs: list[str], name: str) -> Path | None:
|
||||
for d in dirs:
|
||||
p = vault / d / name
|
||||
if p.is_file():
|
||||
return p
|
||||
hits = [p for p in vault.rglob(name) if ".obsidian" not in p.parts]
|
||||
return hits[0] if hits else None
|
||||
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("-w", "--write", action="store_true", help="write changes (default: dry run)")
|
||||
ap.add_argument("-d", "--diff", action="store_true", help="show a unified diff for changed notes")
|
||||
ap.add_argument("--vault", type=Path, help="override vault path from the config")
|
||||
ap.add_argument("--repo", type=Path, help="override repo path (default: parent of scripts/)")
|
||||
args = ap.parse_args()
|
||||
|
||||
cfg = json.loads(CONFIG_PATH.read_text(encoding="utf-8"))
|
||||
env = load_env(ENV_PATH)
|
||||
if "OBSIDIAN_EXCLUDE_SECTIONS" in env:
|
||||
cfg["exclude_sections"] = [h.strip() for h in env["OBSIDIAN_EXCLUDE_SECTIONS"].split(";") if h.strip()]
|
||||
if env.get("OBSIDIAN_IMAGE_DIRS"):
|
||||
cfg["image_dirs"] = [d.strip() for d in env["OBSIDIAN_IMAGE_DIRS"].split(";") if d.strip()]
|
||||
if not args.vault and not env.get("OBSIDIAN_VAULT"):
|
||||
print(f"OBSIDIAN_VAULT is not set. Copy {ENV_PATH.with_name('.env.example').name} "
|
||||
f"to {ENV_PATH.name} in {SCRIPT_DIR} and set your vault path.", file=sys.stderr)
|
||||
return 1
|
||||
vault = args.vault or Path(env["OBSIDIAN_VAULT"])
|
||||
repo = args.repo or (Path(cfg["repo"]) if cfg.get("repo") else SCRIPT_DIR.parent)
|
||||
if not vault.is_dir() or not repo.is_dir():
|
||||
print(f"Vault or repo not found:\n vault: {vault}\n repo: {repo}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
conv = Converter(cfg, vault)
|
||||
fmt = Formatter(cfg.get("formatter"), conv.warnings)
|
||||
changed = 0
|
||||
print(f"{'WRITE' if args.write else 'DRY RUN'} vault: {vault}\n{' ' * 9}repo: {repo}\n")
|
||||
|
||||
for note in cfg["notes"]:
|
||||
src, dst = vault / note["source"], repo / note["target"]
|
||||
if not src.is_file():
|
||||
conv.warnings.append(f"missing in vault: {note['source']}")
|
||||
continue
|
||||
new = conv.convert(read_text(src), note["source"])
|
||||
if note.get("title"): # replace or add the H1
|
||||
if new.startswith("# "):
|
||||
new = f"# {note['title']}\n" + new.split("\n", 1)[1]
|
||||
else:
|
||||
new = f"# {note['title']}\n\n" + new
|
||||
try:
|
||||
old = read_text(dst) if dst.exists() else None
|
||||
except PermissionError:
|
||||
conv.warnings.append(f"cannot read {note['target']} (permission denied), skipped")
|
||||
continue
|
||||
new = fmt(new, note["target"])
|
||||
|
||||
if new == old:
|
||||
print(f" unchanged {note['target']}")
|
||||
continue
|
||||
changed += 1
|
||||
print(f" {'new ' if old is None else 'changed '} {note['target']}")
|
||||
if args.diff:
|
||||
sys.stdout.writelines(difflib.unified_diff(
|
||||
(old or "").splitlines(True), new.splitlines(True),
|
||||
f"repo/{note['target']}", f"vault/{note['source']}"))
|
||||
print()
|
||||
if args.write:
|
||||
dst.write_text(new, encoding="utf-8", newline="\n")
|
||||
|
||||
assets = repo / cfg.get("assets_dir", "assets")
|
||||
for name in sorted(conv.images):
|
||||
src = find_image(vault, cfg.get("image_dirs", []), name)
|
||||
if not src:
|
||||
conv.warnings.append(f"image not found in vault: {name}")
|
||||
continue
|
||||
dst = assets / name
|
||||
if dst.exists() and filecmp.cmp(src, dst, shallow=False):
|
||||
continue
|
||||
changed += 1
|
||||
print(f" {'changed ' if dst.exists() else 'new '} {cfg.get('assets_dir', 'assets')}/{name}")
|
||||
if args.write:
|
||||
assets.mkdir(exist_ok=True)
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
if conv.warnings:
|
||||
print("\nWarnings:")
|
||||
for w in conv.warnings:
|
||||
print(f" - {w}")
|
||||
print(f"\n{changed} file(s) {'written' if args.write else 'would change'}."
|
||||
+ ("" if args.write or not changed else " Run with --write to apply."))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in New Issue
Block a user