mirror of
https://gitea.invidious.io/iv-org/invidious-copy-2023-06-08.git
synced 2024-08-15 00:53:38 +00:00
Videos: Create some base classes for streams
This commit is contained in:
parent
cbbec00e1c
commit
365330f1d9
1 changed files with 267 additions and 0 deletions
267
src/invidious/videos/streams.cr
Normal file
267
src/invidious/videos/streams.cr
Normal file
|
@ -0,0 +1,267 @@
|
||||||
|
module Invidious::Videos
|
||||||
|
# ------------------
|
||||||
|
# Structs & Enums
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
# "AUDIO_QUALITY_"
|
||||||
|
enum AudioQuality
|
||||||
|
Low
|
||||||
|
Medium
|
||||||
|
end
|
||||||
|
|
||||||
|
enum ProjType
|
||||||
|
Rectangular
|
||||||
|
Equirectangular
|
||||||
|
Mesh
|
||||||
|
end
|
||||||
|
|
||||||
|
struct ByteRange
|
||||||
|
getter start : UInt32
|
||||||
|
getter end : UInt32
|
||||||
|
|
||||||
|
def initialize(@start, @end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
return "#{@start}-#{@end}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------
|
||||||
|
# Traits
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
# Properties common to all streams containing audio
|
||||||
|
module AudioProperties
|
||||||
|
macro included
|
||||||
|
property audio_quality : AudioQuality
|
||||||
|
property audio_sample_rate : UInt32
|
||||||
|
property audio_channels : UInt8
|
||||||
|
property audio_loudness_db : Float64 = 0.0
|
||||||
|
|
||||||
|
private macro init_audio_properties(format)
|
||||||
|
@audio_quality = AudioQuality.parse(format["audioQuality"].as_s.lstrip("AUDIO_QUALITY_"))
|
||||||
|
@audio_sample_rate = format["audioSampleRate"].as_s.to_u32
|
||||||
|
@audio_channels = format["audioChannels"].as_i.to_u8
|
||||||
|
@audio_loudness_db = format["loudnessDb"]?.try &.as_f || 0.0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Properties common to all streams containing video
|
||||||
|
module VideoProperties
|
||||||
|
macro included
|
||||||
|
property video_width : UInt32
|
||||||
|
property video_height : UInt32
|
||||||
|
property video_fps : UInt16
|
||||||
|
|
||||||
|
private macro init_video_properties(format)
|
||||||
|
@video_width = format["width"].as_i.to_u32
|
||||||
|
@video_height = format["height"].as_i.to_u32
|
||||||
|
@video_fps = format["fps"].as_i.to_u16
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Properties common to all audio & video streams
|
||||||
|
module AVCommonProperties
|
||||||
|
macro included
|
||||||
|
property bitrate : UInt64
|
||||||
|
property bitrate_avg : UInt64?
|
||||||
|
property content_length : UInt64
|
||||||
|
|
||||||
|
private macro init_av_common_properties(format)
|
||||||
|
@bitrate = format["bitrate"].as_i.to_u64
|
||||||
|
@bitrate_avg = format["averageBitrate"]?.try &.as_i.to_u64
|
||||||
|
@content_length = format["contentLength"].as_s.to_u64
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Properties that only applies to mulit-lingual adaptative streams.
|
||||||
|
# They apply to audio and text streams (notably text/mp4).
|
||||||
|
#
|
||||||
|
# Sample JSON for an audio track:
|
||||||
|
# "audioTrack": {
|
||||||
|
# "displayName": "Arabic",
|
||||||
|
# "id": "ar.0",
|
||||||
|
# "audioIsDefault": false
|
||||||
|
# },
|
||||||
|
#
|
||||||
|
# Sample JSON for a caption track:
|
||||||
|
# "captionTrack": {
|
||||||
|
# "displayName": "English",
|
||||||
|
# "vssId": ".en.eEY6OEpapPo",
|
||||||
|
# "languageCode": "en"
|
||||||
|
# }
|
||||||
|
module TrackProperties
|
||||||
|
macro included
|
||||||
|
property track_id : String?
|
||||||
|
property track_name : String = "default"
|
||||||
|
property iso_code : String?
|
||||||
|
property default : Bool = false
|
||||||
|
|
||||||
|
private macro init_track_properties(format)
|
||||||
|
if audio_track = format["audioTrack"]?
|
||||||
|
id = audio_track["id"].as_s
|
||||||
|
|
||||||
|
@track_id = id
|
||||||
|
@track_name = audio_track["displayName"].as_s
|
||||||
|
|
||||||
|
@iso_code = id.gsub(".0", "")
|
||||||
|
@default = audio_track["audioIsDefault"].as_bool
|
||||||
|
#
|
||||||
|
elsif caption_track = format["captionTrack"]?
|
||||||
|
@track_name = caption_track["displayName"].as_s
|
||||||
|
@track_id = caption_track["vssId"].as_s
|
||||||
|
@iso_code = caption_track["languageCode"].as_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Properties that only apply to adaptative streams of regular videos
|
||||||
|
module AdaptativeProperties
|
||||||
|
macro included
|
||||||
|
property init_range : ByteRange?
|
||||||
|
property index_range : ByteRange?
|
||||||
|
|
||||||
|
private macro init_adaptative_properties(format)
|
||||||
|
if init_range = format["initRange"]?
|
||||||
|
@init_range = ByteRange.new(
|
||||||
|
init_range["start"].as_i.to_u32,
|
||||||
|
init_range["end"].as_i.to_u32
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
if index_range = format["indexRange"]?
|
||||||
|
@index_range = ByteRange.new(
|
||||||
|
index_range["start"].as_i.to_u32,
|
||||||
|
index_range["end"].as_i.to_u32
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Properties that only apply to adaptative streams from livestrams
|
||||||
|
# (either in progress, or recenlty ended)
|
||||||
|
module LiveProperties
|
||||||
|
macro included
|
||||||
|
property target_duration : UInt32?
|
||||||
|
property max_dvr_duration : UInt32?
|
||||||
|
|
||||||
|
private macro init_live_properties(format)
|
||||||
|
@target_duration = format["targetDurationSec"]?.try(&.as_i.to_u32)
|
||||||
|
@max_dvr_duration = format["maxDvrDurationSec"]?.try(&.as_i.to_u32)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------
|
||||||
|
# Base class
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
# Base stream class defining all the common properties for all streams
|
||||||
|
abstract class Stream
|
||||||
|
getter itag : UInt16
|
||||||
|
getter label : String
|
||||||
|
property url : String
|
||||||
|
|
||||||
|
getter raw_mime_type : String
|
||||||
|
getter mime_type : String
|
||||||
|
getter codecs : String
|
||||||
|
|
||||||
|
getter last_modified : Time?
|
||||||
|
|
||||||
|
getter projection_type : ProjType
|
||||||
|
|
||||||
|
def initialize(format : JSON::Any, @label)
|
||||||
|
@itag = format["itag"].as_i.to_u16
|
||||||
|
@url = format["url"].as_s
|
||||||
|
|
||||||
|
@raw_mime_type = format["mimeType"].as_s
|
||||||
|
|
||||||
|
# Extract MIME type and codecs from the raw mimeType string
|
||||||
|
@mime_type, raw_codecs = @raw_mime_type.split(';')
|
||||||
|
@codecs = raw_codecs.lstrip(" codecs=\"").rstrip('"')
|
||||||
|
|
||||||
|
# Last modified is not present on livestreams
|
||||||
|
if last_modified = format["lastModified"].as_s
|
||||||
|
# E.g "1670664306(.)849305"
|
||||||
|
# Note: (.) is not present in the input data, it's used here to show
|
||||||
|
# the demarcation between seconds and microseconds.
|
||||||
|
timestamp = last_modified[0...10]
|
||||||
|
microseconds = last_modified[10..]
|
||||||
|
|
||||||
|
@last_modified = Time.utc(
|
||||||
|
seconds: timestamp.to_i64,
|
||||||
|
nanoseconds: microseconds.to_i * 1000
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
@projection_type = ProjType.parse(format["projectionType"].as_s)
|
||||||
|
|
||||||
|
# Initialize extra properties as required
|
||||||
|
{% begin %}
|
||||||
|
{%
|
||||||
|
properties_types = [
|
||||||
|
AudioProperties,
|
||||||
|
VideoProperties,
|
||||||
|
TrackProperties,
|
||||||
|
AVCommonProperties,
|
||||||
|
AdaptativeProperties,
|
||||||
|
LiveProperties,
|
||||||
|
]
|
||||||
|
%}
|
||||||
|
|
||||||
|
{% for type in properties_types %}
|
||||||
|
# Call the appropriate initialization macro if self
|
||||||
|
# inherits from the given type
|
||||||
|
{% if @type < type %}
|
||||||
|
init_{{type.id.split("::").last.id.underscore}}(format)
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
{% end %}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# ------------------
|
||||||
|
# Children classes
|
||||||
|
# ------------------
|
||||||
|
|
||||||
|
# An HTTP progressive stream (audio + video)
|
||||||
|
class ProgressiveHttpStream < Stream
|
||||||
|
include AudioProperties
|
||||||
|
include VideoProperties
|
||||||
|
include AVCommonProperties
|
||||||
|
end
|
||||||
|
|
||||||
|
# Base class for adaptative (DASH) streams
|
||||||
|
abstract class AdaptativeStream < Stream
|
||||||
|
include AdaptativeProperties
|
||||||
|
include LiveProperties
|
||||||
|
end
|
||||||
|
|
||||||
|
# An audio-only adaptative (DASH) stream
|
||||||
|
class AdaptativeAudioStream < AdaptativeStream
|
||||||
|
include AudioProperties
|
||||||
|
include AVCommonProperties
|
||||||
|
end
|
||||||
|
|
||||||
|
# An audio-only adaptative (DASH) stream with track informations
|
||||||
|
class AdaptativeAudioTrackStream < AdaptativeAudioStream
|
||||||
|
include TrackProperties
|
||||||
|
end
|
||||||
|
|
||||||
|
# A video-only adaptative (DASH) stream
|
||||||
|
class AdaptativeVideoStream < AdaptativeStream
|
||||||
|
include VideoProperties
|
||||||
|
include AVCommonProperties
|
||||||
|
end
|
||||||
|
|
||||||
|
# A text-only adaptative (DASH) stream
|
||||||
|
class AdaptativeTextStream < AdaptativeStream
|
||||||
|
include TrackProperties
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue