Implementing a streaming setup with Usenet
This commit is contained in:
@@ -1,5 +1,16 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func RemoveItem[S ~[]E, E comparable](s S, values ...E) S {
|
||||
result := make(S, 0, len(s))
|
||||
outer:
|
||||
@@ -22,3 +33,131 @@ func Contains(slice []string, value string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func GenerateHash(data string) string {
|
||||
// Simple hash generation using a basic algorithm (for demonstration purposes)
|
||||
_hash := 0
|
||||
for _, char := range data {
|
||||
_hash = (_hash*31 + int(char)) % 1000003 // Simple hash function
|
||||
}
|
||||
return string(rune(_hash))
|
||||
}
|
||||
|
||||
func DownloadFile(url string) (string, []byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to download file: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", nil, fmt.Errorf("failed to download file: status code %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
filename := getFilenameFromResponse(resp, url)
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
|
||||
return filename, data, nil
|
||||
}
|
||||
|
||||
func getFilenameFromResponse(resp *http.Response, originalURL string) string {
|
||||
// 1. Try Content-Disposition header
|
||||
if cd := resp.Header.Get("Content-Disposition"); cd != "" {
|
||||
if _, params, err := mime.ParseMediaType(cd); err == nil {
|
||||
if filename := params["filename"]; filename != "" {
|
||||
return filename
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try to decode URL-encoded filename from Content-Disposition
|
||||
if cd := resp.Header.Get("Content-Disposition"); cd != "" {
|
||||
if strings.Contains(cd, "filename*=") {
|
||||
// Handle RFC 5987 encoded filenames
|
||||
parts := strings.Split(cd, "filename*=")
|
||||
if len(parts) > 1 {
|
||||
encoded := strings.Trim(parts[1], `"`)
|
||||
if strings.HasPrefix(encoded, "UTF-8''") {
|
||||
if decoded, err := url.QueryUnescape(encoded[7:]); err == nil {
|
||||
return decoded
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fall back to URL path
|
||||
if parsedURL, err := url.Parse(originalURL); err == nil {
|
||||
if filename := filepath.Base(parsedURL.Path); filename != "." && filename != "/" {
|
||||
// URL decode the filename
|
||||
if decoded, err := url.QueryUnescape(filename); err == nil {
|
||||
return decoded
|
||||
}
|
||||
return filename
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Default filename
|
||||
return "downloaded_file"
|
||||
}
|
||||
|
||||
func ValidateServiceURL(urlStr string) error {
|
||||
if urlStr == "" {
|
||||
return fmt.Errorf("URL cannot be empty")
|
||||
}
|
||||
|
||||
// Try parsing as full URL first
|
||||
u, err := url.Parse(urlStr)
|
||||
if err == nil && u.Scheme != "" && u.Host != "" {
|
||||
// It's a full URL, validate scheme
|
||||
if u.Scheme != "http" && u.Scheme != "https" {
|
||||
return fmt.Errorf("URL scheme must be http or https")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if it's a host:port format (no scheme)
|
||||
if strings.Contains(urlStr, ":") && !strings.Contains(urlStr, "://") {
|
||||
// Try parsing with http:// prefix
|
||||
testURL := "http://" + urlStr
|
||||
u, err := url.Parse(testURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid host:port format: %w", err)
|
||||
}
|
||||
|
||||
if u.Host == "" {
|
||||
return fmt.Errorf("host is required in host:port format")
|
||||
}
|
||||
|
||||
// Validate port number
|
||||
if u.Port() == "" {
|
||||
return fmt.Errorf("port is required in host:port format")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("invalid URL format: %s", urlStr)
|
||||
}
|
||||
|
||||
func ExtractFilenameFromURL(rawURL string) string {
|
||||
// Parse the URL
|
||||
parsedURL, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get the base filename from path
|
||||
filename := path.Base(parsedURL.Path)
|
||||
|
||||
// Handle edge cases
|
||||
if filename == "/" || filename == "." || filename == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
return filename
|
||||
}
|
||||
|
||||
@@ -57,3 +57,15 @@ func IsSampleFile(path string) bool {
|
||||
}
|
||||
return RegexMatch(sampleRegex, path)
|
||||
}
|
||||
|
||||
func IsParFile(path string) bool {
|
||||
ext := filepath.Ext(path)
|
||||
return strings.EqualFold(ext, ".par") || strings.EqualFold(ext, ".par2")
|
||||
}
|
||||
|
||||
func IsRarFile(path string) bool {
|
||||
ext := filepath.Ext(path)
|
||||
return strings.EqualFold(ext, ".rar") || strings.EqualFold(ext, ".r00") ||
|
||||
strings.EqualFold(ext, ".r01") || strings.EqualFold(ext, ".r02") ||
|
||||
strings.EqualFold(ext, ".r03") || strings.EqualFold(ext, ".r04")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user