Skip to content

Commit

Permalink
Merge pull request #1 from firofame/improve-code
Browse files Browse the repository at this point in the history
Improve code quality and performance
  • Loading branch information
firofame authored Nov 9, 2024
2 parents d78c338 + ed1ee70 commit 0a0c8ca
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 63 deletions.
7 changes: 7 additions & 0 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ jobs:
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
Expand Down
83 changes: 49 additions & 34 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,51 +2,66 @@
import re
import requests

# Read the handles from a file
with open('handles.txt', 'r') as f:
handles = [tuple(line.strip().split(',')) for line in f]
def read_handles(file_path):
with open(file_path, 'r') as f:
return [tuple(line.strip().split(',')) for line in f]

# Create an empty list to store the channel data
channel_data = []

# Write the playlist file
with open('playlist.m3u', 'w') as f:
f.write('#EXTM3U\n')
for i, (handle, group) in enumerate(handles, start=1):
# Construct the URL for the channel's live stream
url = f'https://www.youtube.com/@{handle}/live'

# Send a GET request to the URL
def fetch_channel_data(handle):
url = f'https://www.youtube.com/@{handle}/live'
try:
response = requests.get(url)
response.raise_for_status()
except requests.RequestException as e:
print(f"Error fetching data for handle {handle}: {e}")
return None

# Search for the ytInitialData variable in the page source
match = re.search(r'var ytInitialData = ({.*?});', response.text)
match = re.search(r'var ytInitialData = ({.*?});', response.text)
if not match:
print(f"No ytInitialData found for handle {handle}")
return None

# Extract the JSON data from the match
try:
json_data = match.group(1)

# Parse the JSON data
data = json.loads(json_data)
except json.JSONDecodeError as e:
print(f"Error parsing JSON data for handle {handle}: {e}")
return None

# Extract the channel name and image URL
try:
channel_name = data['contents']['twoColumnWatchNextResults']['results']['results']['contents'][1]['videoSecondaryInfoRenderer']['owner']['videoOwnerRenderer']['title']['runs'][0]['text']
image_url = data['contents']['twoColumnWatchNextResults']['results']['results']['contents'][1]['videoSecondaryInfoRenderer']['owner']['videoOwnerRenderer']['thumbnail']['thumbnails'][-1]['url']

# Extract the channel ID
channel_id = data['contents']['twoColumnWatchNextResults']['results']['results']['contents'][1]['videoSecondaryInfoRenderer']['owner']['videoOwnerRenderer']['title']['runs'][0]['navigationEndpoint']['browseEndpoint']['browseId']
except (KeyError, IndexError) as e:
print(f"Error extracting channel data for handle {handle}: {e}")
return None

# Construct the M3U8 URL for the channel's live stream
m3u8_url = f'https://ythls.armelin.one/channel/{channel_id}.m3u8'
return {
'channel_name': channel_name,
'image_url': image_url,
'channel_id': channel_id
}

# Write the metadata and URL to the playlist file
f.write(f'#EXTINF:-1 tvg-logo="{image_url}" group-title="{group}", {channel_name}\n{m3u8_url}\n')
def write_playlist(file_path, handles):
with open(file_path, 'w') as f:
f.write('#EXTM3U\n')
for handle, group in handles:
channel_data = fetch_channel_data(handle)
if channel_data:
m3u8_url = f'https://ythls.armelin.one/channel/{channel_data["channel_id"]}.m3u8'
f.write(f'#EXTINF:-1 tvg-logo="{channel_data["image_url"]}" group-title="{group}", {channel_data["channel_name"]}\n{m3u8_url}\n')

# Add the channel data to the list
channel_data.append({
'channel_name': channel_name,
'channel_id': channel_id
})
def write_channel_data(file_path, handles):
channel_data = []
for handle, group in handles:
data = fetch_channel_data(handle)
if data:
channel_data.append({
'channel_name': data['channel_name'],
'channel_id': data['channel_id']
})
with open(file_path, 'w') as f:
json.dump(channel_data, f)

# Write the channel data to a JSON file
with open('playlist.json', 'w') as f:
json.dump(channel_data, f)
handles = read_handles('handles.txt')
write_playlist('playlist.m3u', handles)
write_channel_data('playlist.json', handles)
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YouTube Live Stream Viewer</title>
<title>YouTube Live Stream Channel Viewer</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
Expand All @@ -18,4 +18,4 @@

<script src="youtube-player.js"></script>
</body>
</html>
</html>
8 changes: 4 additions & 4 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ iframe {
max-height: 30%;
overflow-y: auto;
}
button {
#button-container button {
margin: 5px;
padding: 10px;
font-size: 14px;
Expand All @@ -41,9 +41,9 @@ button {
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
#button-container button:hover {
background-color: #45a049;
}
button.active {
#button-container button.active {
background-color: #007bff;
}
}
53 changes: 30 additions & 23 deletions youtube-player.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,40 @@ const iframe = document.getElementById('youtube-iframe');
let buttons = document.querySelectorAll('#button-container button');

async function loadPlaylist() {
const response = await fetch('playlist.json');
const playlist = await response.json();
try {
const response = await fetch('playlist.json');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const playlist = await response.json();

function changeChannel(channelId) {
iframe.src = `https://www.youtube.com/embed/live_stream?channel=${channelId}&autoplay=1`;
localStorage.setItem('lastChannel', channelId);
updateActiveButton(channelId);
}
function changeChannel(channelId) {
iframe.src = `https://www.youtube.com/embed/live_stream?channel=${channelId}&autoplay=1`;
localStorage.setItem('lastChannel', channelId);
updateActiveButton(channelId);
}

function updateActiveButton(channelId) {
buttons.forEach(btn => {
btn.classList.toggle('active', btn.dataset.channel === channelId);
});
}
function updateActiveButton(channelId) {
buttons.forEach(btn => {
btn.classList.toggle('active', btn.dataset.channel === channelId);
});
}

const lastChannel = localStorage.getItem('lastChannel') || playlist[1].channel_id;
changeChannel(lastChannel);
const lastChannel = localStorage.getItem('lastChannel') || playlist[1].channel_id;
changeChannel(lastChannel);

const buttonContainer = document.getElementById('button-container');
playlist.forEach(channel => {
const button = document.createElement('button');
button.dataset.channel = channel.channel_id;
button.textContent = channel.channel_name;
button.addEventListener('click', () => changeChannel(channel.channel_id));
buttonContainer.appendChild(button);
});
buttons = document.querySelectorAll('#button-container button');
const buttonContainer = document.getElementById('button-container');
playlist.forEach(channel => {
const button = document.createElement('button');
button.dataset.channel = channel.channel_id;
button.textContent = channel.channel_name;
button.addEventListener('click', () => changeChannel(channel.channel_id));
buttonContainer.appendChild(button);
});
buttons = document.querySelectorAll('#button-container button');
} catch (error) {
console.error('Error loading playlist:', error);
}
}

loadPlaylist();

0 comments on commit 0a0c8ca

Please sign in to comment.