Skip to content

Commit 1e2ff2d

Browse files
committed
[plugin.audio.c3lounge] v1.0.0
1 parent 3e58dcd commit 1e2ff2d

File tree

7 files changed

+277
-0
lines changed

7 files changed

+277
-0
lines changed

plugin.audio.c3lounge/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# c3lounge Radio Kodi Addon
2+
3+
Stream c3lounge Radio directly in Kodi!
4+
5+
## Features
6+
7+
- 🎵 Live radio streaming from c3lounge.de
8+
9+
## Installation
10+
11+
### Method 1: Install from ZIP
12+
13+
1. Download the addon as a ZIP file
14+
2. In Kodi, go to: **Settings****Add-ons****Install from zip file**
15+
3. Select the downloaded ZIP file
16+
4. Wait for the "Add-on enabled" notification
17+
18+
### Method 2: Manual Installation
19+
20+
1. Copy the `plugin.audio.c3lounge` folder to your Kodi addons directory:
21+
- **Linux**: `~/.kodi/addons/`
22+
- **Linux Flatpak**: `~/.var/app/tv.kodi.Kodi/data/addons/`
23+
24+
2. Restart Kodi or enable the addon from: **Settings****Add-ons****My add-ons****Music add-ons****c3lounge Radio**
25+
26+
## Usage
27+
28+
1. Launch the addon from **Add-ons****Music add-ons****c3lounge Radio**
29+
2. Select "Play c3lounge Radio" to start streaming
30+
31+
## Requirements
32+
33+
- Kodi 19 (Matrix) or newer
34+
- Internet connection
35+
- script.module.requests (automatically installed as dependency)
36+
37+
## Troubleshooting
38+
39+
### Stream won't play
40+
- Check your internet connection
41+
- Verify c3lounge.de is accessible
42+
- Check Kodi logs for error messages
43+

plugin.audio.c3lounge/addon.py

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
import sys
5+
import xbmc
6+
import xbmcgui
7+
import xbmcplugin
8+
import xbmcaddon
9+
import requests
10+
from urllib.parse import urlencode, parse_qsl
11+
12+
# Addon info
13+
ADDON = xbmcaddon.Addon()
14+
ADDON_ID = ADDON.getAddonInfo('id')
15+
ADDON_NAME = ADDON.getAddonInfo('name')
16+
ADDON_VERSION = ADDON.getAddonInfo('version')
17+
18+
# Base URL for c3lounge
19+
BASE_URL = "https://c3lounge.de"
20+
STREAM_BASE_URL = "https://live.c3lounge.de:8000"
21+
API_URL = f"{STREAM_BASE_URL}/status-json.xsl"
22+
23+
24+
def log(msg, level=xbmc.LOGINFO):
25+
"""Log message to Kodi log"""
26+
xbmc.log(f"[{ADDON_ID}] {msg}", level)
27+
28+
29+
def get_url(**kwargs):
30+
"""Create a URL for calling the plugin"""
31+
return f"{sys.argv[0]}?{urlencode(kwargs)}"
32+
33+
34+
def get_now_playing():
35+
"""Get now playing information from Icecast API"""
36+
try:
37+
response = requests.get(API_URL, timeout=10)
38+
response.raise_for_status()
39+
data = response.json()
40+
41+
# Icecast returns data in icestats.source array
42+
if 'icestats' in data and 'source' in data['icestats']:
43+
sources = data['icestats']['source']
44+
if isinstance(sources, list) and len(sources) > 0:
45+
# Return the first mp3 stream source with metadata
46+
for source in sources:
47+
if 'artist' in source and 'title' in source:
48+
return source
49+
return sources[0]
50+
return sources
51+
return None
52+
except Exception as e:
53+
log(f"Error fetching now playing data: {e}", xbmc.LOGERROR)
54+
return None
55+
56+
57+
def get_stream_url():
58+
"""Get the stream URL from the station info"""
59+
try:
60+
# Get quality setting
61+
quality = ADDON.getSetting('stream_quality')
62+
63+
# Map quality to stream format
64+
quality_map = {
65+
'High': '192.mp3', # 192kbps MP3
66+
'Medium': '64.opus', # 64kbps OPUS
67+
'Low': '32.opus' # 32kbps OPUS
68+
}
69+
70+
stream_file = quality_map.get(quality, '192.mp3')
71+
return f"{STREAM_BASE_URL}/{stream_file}"
72+
73+
except Exception as e:
74+
log(f"Error getting stream URL: {e}", xbmc.LOGERROR)
75+
return f"{STREAM_BASE_URL}/192.mp3"
76+
77+
78+
def play_stream():
79+
"""Play the radio stream"""
80+
stream_url = get_stream_url()
81+
log(f"Playing stream: {stream_url}")
82+
83+
# Get now playing info for metadata
84+
now_playing = get_now_playing()
85+
86+
# Create list item
87+
list_item = xbmcgui.ListItem(path=stream_url)
88+
list_item.setProperty('IsPlayable', 'true')
89+
90+
# Set metadata if available
91+
if now_playing:
92+
try:
93+
# Icecast provides artist and title directly
94+
title = now_playing.get('title', 'c3lounge Radio')
95+
artist = now_playing.get('artist', '')
96+
97+
list_item.setInfo('music', {
98+
'title': title,
99+
'artist': artist,
100+
'mediatype': 'song'
101+
})
102+
103+
log(f"Now playing: {artist} - {title}")
104+
except Exception as e:
105+
log(f"Error setting metadata: {e}", xbmc.LOGERROR)
106+
107+
list_item.setContentLookup(False)
108+
109+
# Play the stream
110+
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem=list_item)
111+
112+
113+
def show_now_playing():
114+
"""Show now playing information"""
115+
now_playing = get_now_playing()
116+
117+
if now_playing:
118+
try:
119+
# Icecast provides artist and title directly
120+
title = now_playing.get('title', 'Unknown')
121+
artist = now_playing.get('artist', 'Unknown')
122+
listeners = now_playing.get('listeners', 0)
123+
124+
message = f"Artist: {artist}\nTitle: {title}"
125+
message += f"\n\nListeners: {listeners}"
126+
127+
xbmcgui.Dialog().ok('Now Playing', message)
128+
except Exception as e:
129+
log(f"Error showing now playing: {e}", xbmc.LOGERROR)
130+
xbmcgui.Dialog().ok('Error', 'Could not fetch now playing information')
131+
else:
132+
xbmcgui.Dialog().ok('Error', 'Could not fetch now playing information')
133+
134+
135+
def list_categories():
136+
"""List available categories/actions"""
137+
# Add "Play c3lounge Radio" item
138+
list_item = xbmcgui.ListItem(label="Play c3lounge Radio")
139+
list_item.setProperty('IsPlayable', 'true')
140+
list_item.setInfo('music', {
141+
'title': 'c3lounge Radio Stream',
142+
'mediatype': 'song'
143+
})
144+
url = get_url(action='play')
145+
xbmcplugin.addDirectoryItem(int(sys.argv[1]), url, list_item, False)
146+
147+
xbmcplugin.endOfDirectory(int(sys.argv[1]))
148+
149+
150+
def router(paramstring):
151+
"""Route to the appropriate function based on the provided paramstring"""
152+
params = dict(parse_qsl(paramstring))
153+
154+
if not params:
155+
# No parameters - show main menu
156+
list_categories()
157+
else:
158+
action = params.get('action')
159+
160+
if action == 'play':
161+
play_stream()
162+
elif action == 'nowplaying':
163+
show_now_playing()
164+
# Refresh the directory to go back to menu
165+
xbmc.executebuiltin('Container.Refresh')
166+
else:
167+
list_categories()
168+
169+
170+
if __name__ == '__main__':
171+
log(f"Starting {ADDON_NAME} v{ADDON_VERSION}")
172+
router(sys.argv[2][1:])

plugin.audio.c3lounge/addon.xml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<addon id="plugin.audio.c3lounge"
3+
name="c3lounge Radio"
4+
version="1.0.0"
5+
provider-name="razze">
6+
<requires>
7+
<import addon="xbmc.python" version="3.0.0"/>
8+
<import addon="script.module.requests" version="2.22.0"/>
9+
</requires>
10+
<extension point="xbmc.python.pluginsource" library="addon.py">
11+
<provides>audio</provides>
12+
</extension>
13+
<extension point="xbmc.addon.metadata">
14+
<summary lang="en_GB">Stream c3lounge Radio</summary>
15+
<description lang="en_GB">Listen to c3lounge Radio from c3lounge.de.</description>
16+
<platform>all</platform>
17+
<license>MIT</license>
18+
<website>https://c3lounge.de/</website>
19+
<news>v1.0.0 (2025-12-31)
20+
- Initial release
21+
</news>
22+
<assets>
23+
<icon>icon.png</icon>
24+
<fanart>fanart.jpg</fanart>
25+
</assets>
26+
</extension>
27+
</addon>

plugin.audio.c3lounge/fanart.jpg

98 KB
Loading

plugin.audio.c3lounge/icon.png

184 KB
Loading
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Kodi Media Center language file
2+
# Addon Name: c3lounge Radio
3+
# Addon id: plugin.audio.c3lounge
4+
msgid ""
5+
msgstr ""
6+
"Project-Id-Version: plugin.audio.c3lounge\n"
7+
"Report-Msgid-Bugs-To: \n"
8+
"POT-Creation-Date: 2025-12-31 12:00+0000\n"
9+
"PO-Revision-Date: 2025-12-31 12:00+0000\n"
10+
"Last-Translator: \n"
11+
"Language-Team: English\n"
12+
"Language: en_GB\n"
13+
"MIME-Version: 1.0\n"
14+
"Content-Type: text/plain; charset=UTF-8\n"
15+
"Content-Transfer-Encoding: 8bit\n"
16+
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
17+
18+
msgctxt "#30000"
19+
msgid "General"
20+
msgstr ""
21+
22+
msgctxt "#30001"
23+
msgid "Stream Settings"
24+
msgstr ""
25+
26+
msgctxt "#30002"
27+
msgid "Stream Quality"
28+
msgstr ""
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
2+
<settings>
3+
<category label="30000">
4+
<setting label="30001" type="lsep"/>
5+
<setting id="stream_quality" type="select" label="30002" values="High|Medium|Low" default="High"/>
6+
</category>
7+
</settings>

0 commit comments

Comments
 (0)