From 25ef2adf7182a00c6b67bdb453e1012d546b28ef Mon Sep 17 00:00:00 2001 From: Seth Van Niekerk Date: Thu, 15 Jan 2026 14:59:52 -0500 Subject: [PATCH] force flag, will overwrite existing light/lightcolour logos with dark/primary --- README.md | 6 ++++-- update_channel_logos.py | 41 ++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 9b2f3c1..d746ec4 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ python update_channel_logos.py \ | `--execute` | Actually perform the changes (without this, runs in dry-run mode) | | `--first-only` | Only process the first channel (useful for testing) | | `--clear` | Clear all logos instead of copying them | +| `--force` | Overwrite existing LogoLight/LogoLightColor (copy mode only) | ## Examples @@ -102,7 +103,7 @@ python update_channel_logos.py \ 3. For each channel: - **Copy mode**: Downloads the Primary logo and uploads it as LogoLight and LogoLightColor - **Clear mode**: Deletes Primary, LogoLight, and LogoLightColor -4. Skips channels that already have the logos (copy mode) or have no logos (clear mode) +4. Skips channels that already have the logos (copy mode, unless `--force` is used) or have no logos (clear mode) 5. Shows a summary of results ## Safety Features @@ -110,7 +111,8 @@ python update_channel_logos.py \ - **Dry run by default**: Always runs in simulation mode unless `--execute` is specified - **Confirmation prompt**: Asks for confirmation before executing changes - **First-only testing**: Test on a single channel before processing all channels -- **Skip existing**: In copy mode, skips channels that already have both light logos +- **Skip existing**: In copy mode, skips channels that already have both light logos (unless `--force` is used) +- **Force mode**: Use `--force` to overwrite existing LogoLight/LogoLightColor images with the current Primary logo ## Notes diff --git a/update_channel_logos.py b/update_channel_logos.py index b8c8445..e8f6f67 100644 --- a/update_channel_logos.py +++ b/update_channel_logos.py @@ -92,7 +92,7 @@ class EmbyClient: raise Exception(f"Failed to delete {image_type}: HTTP {e.code} - {error_body}") -def copy_primary_to_light_logos(client: EmbyClient, channel_id: str, channel_name: str, dry_run: bool = True) -> bool: +def copy_primary_to_light_logos(client: EmbyClient, channel_id: str, channel_name: str, dry_run: bool = True, force: bool = False) -> bool: try: channel_data = client.get_channel_by_id(channel_id) image_tags = channel_data.get('ImageTags', {}) @@ -104,29 +104,32 @@ def copy_primary_to_light_logos(client: EmbyClient, channel_id: str, channel_nam has_logo_light = 'LogoLight' in image_tags has_logo_light_color = 'LogoLightColor' in image_tags - if has_logo_light and has_logo_light_color: + if has_logo_light and has_logo_light_color and not force: print(f" ✓ Already has both logos") return True - missing = [] - if not has_logo_light: - missing.append('LogoLight') - if not has_logo_light_color: - missing.append('LogoLightColor') + to_upload = [] + if not has_logo_light or force: + to_upload.append('LogoLight') + if not has_logo_light_color or force: + to_upload.append('LogoLightColor') if dry_run: - print(f" → Would upload: {', '.join(missing)}") + action = "overwrite" if (has_logo_light or has_logo_light_color) and force else "upload" + print(f" → Would {action}: {', '.join(to_upload)}") return True print(f" 📥 Downloading Primary...") primary_image_data = client.download_image(channel_id, 'Primary') - if not has_logo_light: - print(f" 📤 Uploading LogoLight...") + if 'LogoLight' in to_upload: + action = "Overwriting" if has_logo_light else "Uploading" + print(f" 📤 {action} LogoLight...") client.upload_image(channel_id, 'LogoLight', primary_image_data) - if not has_logo_light_color: - print(f" 📤 Uploading LogoLightColor...") + if 'LogoLightColor' in to_upload: + action = "Overwriting" if has_logo_light_color else "Uploading" + print(f" 📤 {action} LogoLightColor...") client.upload_image(channel_id, 'LogoLightColor', primary_image_data) print(f" ✓ Successfully uploaded") @@ -169,7 +172,7 @@ def clear_channel_logos(client: EmbyClient, channel_id: str, channel_name: str, return False -def update_channel_logos(client: EmbyClient, dry_run: bool = True, first_only: bool = False) -> None: +def update_channel_logos(client: EmbyClient, dry_run: bool = True, first_only: bool = False, force: bool = False) -> None: channels = client.get_live_tv_channels() channels_to_process = [channels[0]] if first_only else channels @@ -178,6 +181,8 @@ def update_channel_logos(client: EmbyClient, dry_run: bool = True, first_only: b print(f"{'DRY RUN: TESTING ON' if dry_run else 'PROCESSING'} FIRST CHANNEL ONLY") else: print(f"{'DRY RUN: SIMULATING' if dry_run else 'PROCESSING'} ALL {len(channels)} CHANNELS") + if force: + print("FORCE MODE: Will overwrite existing logos") print("=" * 80) success_count = 0 @@ -185,7 +190,7 @@ def update_channel_logos(client: EmbyClient, dry_run: bool = True, first_only: b for i, channel in enumerate(channels_to_process, 1): print(f"\n[{i}/{len(channels_to_process)}] {channel.get('Name', 'Unknown')}") - if copy_primary_to_light_logos(client, channel['Id'], channel.get('Name'), dry_run): + if copy_primary_to_light_logos(client, channel['Id'], channel.get('Name'), dry_run, force): success_count += 1 else: skip_count += 1 @@ -244,6 +249,7 @@ def main(): parser.add_argument('--execute', action='store_true', help='Actually perform updates') parser.add_argument('--first-only', action='store_true', help='Only process first channel') parser.add_argument('--clear', action='store_true', help='Clear all logos (Primary, LogoLight, LogoLightColor)') + parser.add_argument('--force', action='store_true', help='Overwrite existing logos (only applies to copy mode)') args = parser.parse_args() client = EmbyClient(args.server, args.api_key) @@ -268,12 +274,13 @@ def main(): else: if args.execute: target = "first channel" if args.first_only else "all channels" - if input(f"\nModify {target}? (yes/no): ").lower() == 'yes': - update_channel_logos(client, dry_run=False, first_only=args.first_only) + action = "overwrite logos in" if args.force else "modify" + if input(f"\n{action.capitalize()} {target}? (yes/no): ").lower() == 'yes': + update_channel_logos(client, dry_run=False, first_only=args.first_only, force=args.force) else: print("Cancelled.") else: - update_channel_logos(client, dry_run=True, first_only=args.first_only) + update_channel_logos(client, dry_run=True, first_only=args.first_only, force=args.force) if __name__ == '__main__':