DiscogsDataProcessorCLI 1.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: DiscogsDataProcessorCLI
3
+ Version: 1.5.0
4
+ Summary: A CLI to download, extract and convert Discogs data dumps
5
+ Home-page: https://github.com/ofurkancoban/DiscogsCLI
6
+ Author: Furkan Γ‡oban
7
+ Author-email: ofurkancoban@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: rich
15
+ Requires-Dist: pandas
16
+ Requires-Dist: typer
17
+
18
+ # 🎧 Discogs CLI β€” Data Processor Tool πŸ’Ώ
19
+ <p align="center">
20
+ <img src="img/logo.png" alt="Discogs Logo" width="200"/>
21
+ </p>
22
+ A modern command-line tool to **download**, **extract**, and **convert** Discogs data dumps into structured CSV files.
23
+ <p align="center">
24
+ <img src="img/preview.gif" />
25
+ </p>
26
+
27
+ ---
28
+
29
+ ## πŸš€ Features
30
+
31
+ - 🧠 Scrape latest available data dump list from Discogs S3
32
+ - ⬇️ Download `.gz` files for artists, labels, releases, masters
33
+ - πŸ“¦ Extract `.gz` files to raw XML
34
+ - βœ‚οΈ Chunk large XML into smaller files
35
+ - πŸ“„ Convert XML to clean, flat CSV files
36
+ - πŸ—‘ Delete selected or all files
37
+ - βš™οΈ Set custom download folder
38
+ - πŸ§ͺ Easy to use from terminal with friendly UI
39
+
40
+ ---
41
+
42
+ ## 🧩 Installation
43
+
44
+ ### 🍻 Install with Homebrew
45
+ ```bash
46
+ brew tap ofurkancoban/discogs
47
+ brew install discogs
48
+ ```
49
+ ### or
50
+ ```bash
51
+ git clone https://github.com/ofurkancoban/DiscogsCLI.git
52
+ cd DiscogsCLI
53
+ pip install -e .
54
+ ```
55
+
56
+ ---
57
+
58
+ ## πŸ’» Usage
59
+
60
+ ```bash
61
+ discogs run # Auto: download β†’ extract β†’ convert
62
+ discogs show # List available Discogs data
63
+ discogs download # Just download selected files
64
+ discogs extract # Extract downloaded .gz files
65
+ discogs convert # Convert extracted XML to CSV
66
+ discogs delete # Delete files by selection or --all
67
+ discogs config # Set download folder
68
+ ```
69
+
70
+ ---
71
+
72
+ ## πŸ“ Folder Structure
73
+
74
+ ```
75
+ ~/Downloads/Discogs/
76
+ β”œβ”€β”€ .discogs_config.json
77
+ └── Datasets/
78
+ └── 2025-04/
79
+ β”œβ”€β”€ discogs_20250401_artists.gz
80
+ β”œβ”€β”€ discogs_20250401_artists ← .xml
81
+ └── discogs_20250401_artists.csv ← converted
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 🧠 Example Workflow
87
+
88
+ ```bash
89
+ discogs show
90
+ # [1] 2025-04 | releases | 950 MB
91
+ # [2] 2025-04 | artists | 320 MB
92
+
93
+ discogs download
94
+ # Select 1,2
95
+ # Downloads only
96
+
97
+ discogs extract
98
+ # Select file to extract
99
+
100
+ discogs convert
101
+ # Select XML to convert
102
+ ```
103
+
104
+ ---
105
+
106
+ ## πŸ§‘β€πŸ’» Author
107
+
108
+ - GitHub: [github.com/ofurkancoban](https://github.com/ofurkancoban)
109
+ - LinkedIn: [linkedin.com/in/ofurkancoban](https://linkedin.com/in/ofurkancoban)
110
+ - Kaggle: [kaggle.com/ofurkancoban](https://www.kaggle.com/ofurkancoban)
111
+
112
+ ---
113
+
114
+ ## πŸ“œ License
115
+
116
+ MIT β€” use freely, mention when you do something cool 😎
117
+ ---
118
+
119
+ Built with ❀️ by [@ofurkancoban](https://github.com/ofurkancoban)
@@ -0,0 +1,20 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.cfg
4
+ DiscogsDataProcessorCLI.egg-info/PKG-INFO
5
+ DiscogsDataProcessorCLI.egg-info/SOURCES.txt
6
+ DiscogsDataProcessorCLI.egg-info/dependency_links.txt
7
+ DiscogsDataProcessorCLI.egg-info/entry_points.txt
8
+ DiscogsDataProcessorCLI.egg-info/requires.txt
9
+ DiscogsDataProcessorCLI.egg-info/top_level.txt
10
+ discogs/__init__.py
11
+ discogs/chunker.py
12
+ discogs/config.py
13
+ discogs/converter.py
14
+ discogs/deleter.py
15
+ discogs/downloader.py
16
+ discogs/extractor.py
17
+ discogs/main.py
18
+ discogs/scraper.py
19
+ discogs/selector.py
20
+ discogs/utils.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ discogs = discogs.main:main
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: DiscogsDataProcessorCLI
3
+ Version: 1.5.0
4
+ Summary: A CLI to download, extract and convert Discogs data dumps
5
+ Home-page: https://github.com/ofurkancoban/DiscogsCLI
6
+ Author: Furkan Γ‡oban
7
+ Author-email: ofurkancoban@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: rich
15
+ Requires-Dist: pandas
16
+ Requires-Dist: typer
17
+
18
+ # 🎧 Discogs CLI β€” Data Processor Tool πŸ’Ώ
19
+ <p align="center">
20
+ <img src="img/logo.png" alt="Discogs Logo" width="200"/>
21
+ </p>
22
+ A modern command-line tool to **download**, **extract**, and **convert** Discogs data dumps into structured CSV files.
23
+ <p align="center">
24
+ <img src="img/preview.gif" />
25
+ </p>
26
+
27
+ ---
28
+
29
+ ## πŸš€ Features
30
+
31
+ - 🧠 Scrape latest available data dump list from Discogs S3
32
+ - ⬇️ Download `.gz` files for artists, labels, releases, masters
33
+ - πŸ“¦ Extract `.gz` files to raw XML
34
+ - βœ‚οΈ Chunk large XML into smaller files
35
+ - πŸ“„ Convert XML to clean, flat CSV files
36
+ - πŸ—‘ Delete selected or all files
37
+ - βš™οΈ Set custom download folder
38
+ - πŸ§ͺ Easy to use from terminal with friendly UI
39
+
40
+ ---
41
+
42
+ ## 🧩 Installation
43
+
44
+ ### 🍻 Install with Homebrew
45
+ ```bash
46
+ brew tap ofurkancoban/discogs
47
+ brew install discogs
48
+ ```
49
+ ### or
50
+ ```bash
51
+ git clone https://github.com/ofurkancoban/DiscogsCLI.git
52
+ cd DiscogsCLI
53
+ pip install -e .
54
+ ```
55
+
56
+ ---
57
+
58
+ ## πŸ’» Usage
59
+
60
+ ```bash
61
+ discogs run # Auto: download β†’ extract β†’ convert
62
+ discogs show # List available Discogs data
63
+ discogs download # Just download selected files
64
+ discogs extract # Extract downloaded .gz files
65
+ discogs convert # Convert extracted XML to CSV
66
+ discogs delete # Delete files by selection or --all
67
+ discogs config # Set download folder
68
+ ```
69
+
70
+ ---
71
+
72
+ ## πŸ“ Folder Structure
73
+
74
+ ```
75
+ ~/Downloads/Discogs/
76
+ β”œβ”€β”€ .discogs_config.json
77
+ └── Datasets/
78
+ └── 2025-04/
79
+ β”œβ”€β”€ discogs_20250401_artists.gz
80
+ β”œβ”€β”€ discogs_20250401_artists ← .xml
81
+ └── discogs_20250401_artists.csv ← converted
82
+ ```
83
+
84
+ ---
85
+
86
+ ## 🧠 Example Workflow
87
+
88
+ ```bash
89
+ discogs show
90
+ # [1] 2025-04 | releases | 950 MB
91
+ # [2] 2025-04 | artists | 320 MB
92
+
93
+ discogs download
94
+ # Select 1,2
95
+ # Downloads only
96
+
97
+ discogs extract
98
+ # Select file to extract
99
+
100
+ discogs convert
101
+ # Select XML to convert
102
+ ```
103
+
104
+ ---
105
+
106
+ ## πŸ§‘β€πŸ’» Author
107
+
108
+ - GitHub: [github.com/ofurkancoban](https://github.com/ofurkancoban)
109
+ - LinkedIn: [linkedin.com/in/ofurkancoban](https://linkedin.com/in/ofurkancoban)
110
+ - Kaggle: [kaggle.com/ofurkancoban](https://www.kaggle.com/ofurkancoban)
111
+
112
+ ---
113
+
114
+ ## πŸ“œ License
115
+
116
+ MIT β€” use freely, mention when you do something cool 😎
117
+ ---
118
+
119
+ Built with ❀️ by [@ofurkancoban](https://github.com/ofurkancoban)
@@ -0,0 +1,102 @@
1
+ # 🎧 Discogs CLI β€” Data Processor Tool πŸ’Ώ
2
+ <p align="center">
3
+ <img src="img/logo.png" alt="Discogs Logo" width="200"/>
4
+ </p>
5
+ A modern command-line tool to **download**, **extract**, and **convert** Discogs data dumps into structured CSV files.
6
+ <p align="center">
7
+ <img src="img/preview.gif" />
8
+ </p>
9
+
10
+ ---
11
+
12
+ ## πŸš€ Features
13
+
14
+ - 🧠 Scrape latest available data dump list from Discogs S3
15
+ - ⬇️ Download `.gz` files for artists, labels, releases, masters
16
+ - πŸ“¦ Extract `.gz` files to raw XML
17
+ - βœ‚οΈ Chunk large XML into smaller files
18
+ - πŸ“„ Convert XML to clean, flat CSV files
19
+ - πŸ—‘ Delete selected or all files
20
+ - βš™οΈ Set custom download folder
21
+ - πŸ§ͺ Easy to use from terminal with friendly UI
22
+
23
+ ---
24
+
25
+ ## 🧩 Installation
26
+
27
+ ### 🍻 Install with Homebrew
28
+ ```bash
29
+ brew tap ofurkancoban/discogs
30
+ brew install discogs
31
+ ```
32
+ ### or
33
+ ```bash
34
+ git clone https://github.com/ofurkancoban/DiscogsCLI.git
35
+ cd DiscogsCLI
36
+ pip install -e .
37
+ ```
38
+
39
+ ---
40
+
41
+ ## πŸ’» Usage
42
+
43
+ ```bash
44
+ discogs run # Auto: download β†’ extract β†’ convert
45
+ discogs show # List available Discogs data
46
+ discogs download # Just download selected files
47
+ discogs extract # Extract downloaded .gz files
48
+ discogs convert # Convert extracted XML to CSV
49
+ discogs delete # Delete files by selection or --all
50
+ discogs config # Set download folder
51
+ ```
52
+
53
+ ---
54
+
55
+ ## πŸ“ Folder Structure
56
+
57
+ ```
58
+ ~/Downloads/Discogs/
59
+ β”œβ”€β”€ .discogs_config.json
60
+ └── Datasets/
61
+ └── 2025-04/
62
+ β”œβ”€β”€ discogs_20250401_artists.gz
63
+ β”œβ”€β”€ discogs_20250401_artists ← .xml
64
+ └── discogs_20250401_artists.csv ← converted
65
+ ```
66
+
67
+ ---
68
+
69
+ ## 🧠 Example Workflow
70
+
71
+ ```bash
72
+ discogs show
73
+ # [1] 2025-04 | releases | 950 MB
74
+ # [2] 2025-04 | artists | 320 MB
75
+
76
+ discogs download
77
+ # Select 1,2
78
+ # Downloads only
79
+
80
+ discogs extract
81
+ # Select file to extract
82
+
83
+ discogs convert
84
+ # Select XML to convert
85
+ ```
86
+
87
+ ---
88
+
89
+ ## πŸ§‘β€πŸ’» Author
90
+
91
+ - GitHub: [github.com/ofurkancoban](https://github.com/ofurkancoban)
92
+ - LinkedIn: [linkedin.com/in/ofurkancoban](https://linkedin.com/in/ofurkancoban)
93
+ - Kaggle: [kaggle.com/ofurkancoban](https://www.kaggle.com/ofurkancoban)
94
+
95
+ ---
96
+
97
+ ## πŸ“œ License
98
+
99
+ MIT β€” use freely, mention when you do something cool 😎
100
+ ---
101
+
102
+ Built with ❀️ by [@ofurkancoban](https://github.com/ofurkancoban)
File without changes
@@ -0,0 +1,95 @@
1
+ # discogs/chunker.py
2
+
3
+ import re
4
+ from pathlib import Path
5
+ from rich.console import Console
6
+ from rich.progress import Progress, BarColumn, TimeElapsedColumn, TextColumn
7
+
8
+
9
+ def sanitize_line(line: str) -> str:
10
+ """
11
+ Removes invalid XML characters and fixes unescaped ampersands.
12
+ This helps ensure the XML is well-formed before processing.
13
+ """
14
+ line = re.sub(r'[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD]', '', line) # Remove illegal XML characters
15
+ line = re.sub(r'&(?![a-zA-Z0-9#]+;)', '&amp;', line) # Escape unescaped '&' characters
16
+ return line
17
+
18
+
19
+ def chunk_xml_by_type(xml_file: Path, content_type: str, records_per_file: int = 10000) -> Path:
20
+ """
21
+ Splits a large XML file into smaller, valid XML files (chunks).
22
+ Each chunk contains up to `records_per_file` XML records.
23
+ Returns the folder path where chunked files are stored.
24
+ """
25
+ record_tag = content_type[:-1].lower() # e.g., "releases" β†’ "release"
26
+ start_pat = re.compile(fr'<{record_tag}\b', re.IGNORECASE) # Match opening tag
27
+ end_pat = re.compile(fr'</{record_tag}>', re.IGNORECASE) # Match closing tag
28
+
29
+ chunk_folder = xml_file.parent / f"chunked_{content_type}" # Output folder
30
+ chunk_folder.mkdir(parents=True, exist_ok=True)
31
+
32
+ console = Console()
33
+ chunk_count = 0
34
+ record_count = 0
35
+ inside_record = False
36
+ buffer_lines = [] # Stores lines of current XML record
37
+ current_chunk_file = None
38
+
39
+ # Helper function to open a new chunk file
40
+ def open_new_chunk():
41
+ nonlocal chunk_count, current_chunk_file, record_count
42
+ chunk_count += 1
43
+ chunk_path = chunk_folder / f"chunk_{chunk_count:05}.xml"
44
+ current_chunk_file = open(chunk_path, "w", encoding="utf-8")
45
+ current_chunk_file.write(f'<?xml version="1.0" encoding="utf-8"?>\n<{content_type}>\n')
46
+ record_count = 0
47
+
48
+ # Helper function to close the current chunk file
49
+ def close_chunk():
50
+ nonlocal current_chunk_file
51
+ if current_chunk_file:
52
+ current_chunk_file.write(f"</{content_type}>")
53
+ current_chunk_file.close()
54
+ current_chunk_file = None
55
+
56
+ open_new_chunk()
57
+
58
+ # Setup progress bar for visual feedback
59
+ with Progress(
60
+ TextColumn("[progress.description]{task.description}"),
61
+ BarColumn(),
62
+ "[progress.percentage]{task.percentage:.1f}%",
63
+ "β€’",
64
+ TimeElapsedColumn()
65
+ ) as progress:
66
+ task = progress.add_task(f"Chunking {xml_file.name}", total=xml_file.stat().st_size)
67
+
68
+ # Read and process XML file line by line
69
+ with xml_file.open("r", encoding="utf-8", errors="ignore") as f:
70
+ for raw_line in f:
71
+ line = sanitize_line(raw_line)
72
+ progress.update(task, advance=len(raw_line))
73
+
74
+ if not inside_record:
75
+ # Detect start of a record
76
+ if start_pat.search(line):
77
+ inside_record = True
78
+ buffer_lines = [line]
79
+ else:
80
+ buffer_lines.append(line)
81
+ if end_pat.search(line):
82
+ # Write complete record to current chunk
83
+ current_chunk_file.write("".join(buffer_lines) + "\n")
84
+ record_count += 1
85
+ inside_record = False
86
+ buffer_lines = []
87
+
88
+ # If chunk is full, start a new one
89
+ if record_count >= records_per_file:
90
+ close_chunk()
91
+ open_new_chunk()
92
+
93
+ close_chunk()
94
+ console.print(f"[green]βœ” Chunked into {chunk_count} file(s): {chunk_folder}")
95
+ return chunk_folder
@@ -0,0 +1,75 @@
1
+ # discogs/config.py
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from rich.console import Console
6
+ from rich.prompt import Prompt
7
+
8
+ CONFIG_PATH = Path.home() / ".discogs_config.json" # Path to the user's config file
9
+ DEFAULT_DOWNLOAD_PATH = Path.home() / "Downloads" / "Discogs" # Default download location
10
+
11
+ console = Console()
12
+
13
+ def get_download_dir() -> Path:
14
+ """
15
+ Returns the download directory from the config file if it exists,
16
+ otherwise returns the default download path.
17
+ """
18
+ if CONFIG_PATH.exists():
19
+ path = CONFIG_PATH.read_text().strip()
20
+ if path:
21
+ return Path(path)
22
+ return DEFAULT_DOWNLOAD_PATH
23
+
24
+ def set_download_dir(path: str) -> None:
25
+ """
26
+ Sets (writes) the download directory path to the config file.
27
+ """
28
+ CONFIG_PATH.write_text(path.strip())
29
+
30
+ def load_config() -> dict:
31
+ """
32
+ Loads configuration data from the config file.
33
+ If the config cannot be read, it returns a dictionary with default values.
34
+ """
35
+ if CONFIG_PATH.exists():
36
+ try:
37
+ with CONFIG_PATH.open("r") as f:
38
+ return json.load(f)
39
+ except Exception as e:
40
+ console.print(f"[red]Error reading config:[/] {e}")
41
+ return {"download_dir": str(DEFAULT_DOWNLOAD_PATH)}
42
+
43
+ def save_config(config: dict) -> None:
44
+ """
45
+ Saves the given configuration dictionary to the config file.
46
+ Creates the parent directory if it doesn't exist.
47
+ """
48
+ CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
49
+ with CONFIG_PATH.open("w") as f:
50
+ json.dump(config, f, indent=4)
51
+
52
+ def get_download_dir() -> Path:
53
+ """
54
+ Gets the download directory from config, falling back to default if missing.
55
+ """
56
+ config = load_config()
57
+ return Path(config.get("download_dir", str(DEFAULT_DOWNLOAD_PATH)))
58
+
59
+ def configure_download_folder() -> None:
60
+ """
61
+ Prompts the user to configure the download folder via CLI.
62
+ Updates the config if a new folder is provided.
63
+ """
64
+ console.print("[bold]Configure Discogs download folder[/bold]")
65
+ current = get_download_dir()
66
+ console.print(f"Current folder: [green]{current}[/green]")
67
+
68
+ new_path = Prompt.ask("Enter new folder path or leave empty to keep current", default=str(current)).strip()
69
+ if new_path:
70
+ new_path = Path(new_path).expanduser()
71
+ new_path.mkdir(parents=True, exist_ok=True)
72
+ save_config({"download_dir": str(new_path)})
73
+ console.print(f"[green]βœ… Download folder updated to:[/] {new_path}")
74
+ else:
75
+ console.print("[yellow]No changes made.[/yellow]")