mirror of
https://github.com/Dvorinka/Trackeep.git
synced 2026-06-04 20:42:59 +00:00
first test
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// YouTubeChannelService handles specific channel integrations
|
||||
type YouTubeChannelService struct {
|
||||
YouTubeService *YouTubeService
|
||||
CacheService *YouTubeCacheService
|
||||
}
|
||||
|
||||
// NewYouTubeChannelService creates a new instance of YouTubeChannelService
|
||||
func NewYouTubeChannelService(youtubeService *YouTubeService, cacheService *YouTubeCacheService) *YouTubeChannelService {
|
||||
return &YouTubeChannelService{
|
||||
YouTubeService: youtubeService,
|
||||
CacheService: cacheService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetPredefinedChannels returns the list of predefined channels
|
||||
func GetPredefinedChannels() []Channel {
|
||||
return []Channel{
|
||||
{
|
||||
ID: "fireship",
|
||||
Name: "Fireship",
|
||||
Description: "Rapid web development tutorials and courses",
|
||||
Thumbnail: "https://img.youtube.com/vi/UCsBjURrPoezykLs9EqgAJVQ/mqdefault.jpg",
|
||||
},
|
||||
{
|
||||
ID: "networkchuck",
|
||||
Name: "NetworkChuck",
|
||||
Description: "Cybersecurity and networking tutorials",
|
||||
Thumbnail: "https://img.youtube.com/vi/UCNlz1cb4DvEx7rTnT2s7B3A/mqdefault.jpg",
|
||||
},
|
||||
{
|
||||
ID: "programmingwithmosh",
|
||||
Name: "Programming with Mosh",
|
||||
Description: "Comprehensive programming tutorials",
|
||||
Thumbnail: "https://img.youtube.com/vi/UC8butUNob-8kuy47X7vH6ws/mqdefault.jpg",
|
||||
},
|
||||
{
|
||||
ID: "traversymedia",
|
||||
Name: "Traversy Media",
|
||||
Description: "Web development and design tutorials",
|
||||
Thumbnail: "https://img.youtube.com/vi/UC29J8QxEQ7QmM0TJ_8Jt_gQ/mqdefault.jpg",
|
||||
},
|
||||
{
|
||||
ID: "thenewboston",
|
||||
Name: "The New Boston",
|
||||
Description: "Computer science and programming courses",
|
||||
Thumbnail: "https://img.youtube.com/vi/UCrwkHaJ-9Sd74Kx1n-9Qjg/mqdefault.jpg",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Channel represents a YouTube channel
|
||||
type Channel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
}
|
||||
|
||||
// GetFireshipVideos fetches latest videos from Fireship channel
|
||||
func (ycs *YouTubeChannelService) GetFireshipVideos(limit int) ([]YouTubeVideo, error) {
|
||||
// Use cached data to avoid rate limiting
|
||||
response, err := ycs.CacheService.GetCachedChannelVideos("fireship", limit)
|
||||
if err != nil {
|
||||
if err.Error() == "YouTube is rate limiting us. Please try again later." {
|
||||
// Return rate limiting error
|
||||
return nil, fmt.Errorf("YouTube is rate limiting us. Please try again later.")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to fetch Fireship videos: %w", err)
|
||||
}
|
||||
|
||||
// Return all videos without filtering
|
||||
return response.Videos, nil
|
||||
}
|
||||
|
||||
// GetNetworkChuckVideos fetches latest videos from Network Chuck channel
|
||||
func (ycs *YouTubeChannelService) GetNetworkChuckVideos(limit int) ([]YouTubeVideo, error) {
|
||||
// Use cached data to avoid rate limiting
|
||||
response, err := ycs.CacheService.GetCachedChannelVideos("networkchuck", limit)
|
||||
if err != nil {
|
||||
if err.Error() == "YouTube is rate limiting us. Please try again later." {
|
||||
// Return rate limiting error
|
||||
return nil, fmt.Errorf("YouTube is rate limiting us. Please try again later.")
|
||||
}
|
||||
return nil, fmt.Errorf("failed to fetch Network Chuck videos: %w", err)
|
||||
}
|
||||
|
||||
// Return all videos without filtering
|
||||
return response.Videos, nil
|
||||
}
|
||||
|
||||
// GetChannelInfo fetches basic information about a channel
|
||||
func (ycs *YouTubeChannelService) GetChannelInfo(channelID string) (*ChannelInfo, error) {
|
||||
// For now, return basic info from predefined channels
|
||||
channels := GetPredefinedChannels()
|
||||
for _, channel := range channels {
|
||||
if channel.ID == channelID {
|
||||
return &ChannelInfo{
|
||||
ID: channel.ID,
|
||||
Title: channel.Name,
|
||||
Description: channel.Description,
|
||||
Thumbnail: channel.Thumbnail,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("channel not found")
|
||||
}
|
||||
|
||||
// ChannelInfo represents basic channel information
|
||||
type ChannelInfo struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Thumbnail string `json:"thumbnail"`
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
|
||||
// parseYouTubeDuration converts ISO 8601 duration string to seconds
|
||||
func parseYouTubeDuration(duration string) int {
|
||||
// YouTube duration format: PT4M13S (4 minutes 13 seconds)
|
||||
// Simple parser for common formats
|
||||
seconds := 0
|
||||
current := 0
|
||||
|
||||
for _, char := range duration {
|
||||
switch char {
|
||||
case 'H', 'h':
|
||||
seconds += current * 3600
|
||||
current = 0
|
||||
case 'M', 'm':
|
||||
seconds += current * 60
|
||||
current = 0
|
||||
case 'S', 's':
|
||||
seconds += current
|
||||
current = 0
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
current = current*10 + int(char-'0')
|
||||
}
|
||||
}
|
||||
|
||||
return seconds
|
||||
}
|
||||
|
||||
func containsIgnoreCase(s, substr string) bool {
|
||||
return len(s) >= len(substr) && (s == substr ||
|
||||
(len(s) > len(substr) &&
|
||||
(s[:len(substr)] == substr ||
|
||||
s[len(s)-len(substr):] == substr ||
|
||||
containsSubstringIgnoreCase(s, substr))))
|
||||
}
|
||||
|
||||
func containsSubstringIgnoreCase(s, substr string) bool {
|
||||
s = toLower(s)
|
||||
substr = toLower(substr)
|
||||
return contains(s, substr)
|
||||
}
|
||||
|
||||
func toLower(s string) string {
|
||||
result := make([]rune, len([]rune(s)))
|
||||
for i, r := range []rune(s) {
|
||||
if r >= 'A' && r <= 'Z' {
|
||||
result[i] = r + ('a' - 'A')
|
||||
} else {
|
||||
result[i] = r
|
||||
}
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func contains(s, substr string) bool {
|
||||
for i := 0; i <= len(s)-len(substr); i++ {
|
||||
if s[i:i+len(substr)] == substr {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isRecentVideo(publishedAt string, months int) bool {
|
||||
// Parse the published date (ISO 8601 format)
|
||||
layout := "2006-01-02T15:04:05Z"
|
||||
publishedTime, err := time.Parse(layout, publishedAt)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if the video is within the specified months
|
||||
cutoffTime := time.Now().AddDate(0, -months, 0)
|
||||
return publishedTime.After(cutoffTime)
|
||||
}
|
||||
Reference in New Issue
Block a user