From c809245724c253e082cf48450a5aa78f0ef42c59 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 5 Jan 2024 22:26:18 -0500 Subject: [PATCH] initial commit of class based arch --- atv/Rakefile.rb | 2 +- atv/atv.gemspec | 13 ++++------ atv/bin/atv | 15 +++++++++++ atv/lib/atv/channel.rb | 33 ++++++++++++++++++++++++ atv/lib/atv/database.rb | 54 +++++++++++++++++++++++++++++++++++++++ atv/lib/atv/player.rb | 43 +++++++++++++++++++++++++++++++ atv/lib/atv/server.rb | 24 +++++++++++++++++ atv/lib/database.rb | 47 ---------------------------------- atv/spec/database_spec.rb | 4 +++ atv/spec/spec_helper.rb | 2 -- 10 files changed, 179 insertions(+), 58 deletions(-) create mode 100755 atv/bin/atv create mode 100644 atv/lib/atv/channel.rb create mode 100644 atv/lib/atv/database.rb create mode 100644 atv/lib/atv/player.rb create mode 100644 atv/lib/atv/server.rb delete mode 100644 atv/lib/database.rb create mode 100644 atv/spec/database_spec.rb diff --git a/atv/Rakefile.rb b/atv/Rakefile.rb index db1be3b..7e2048a 100644 --- a/atv/Rakefile.rb +++ b/atv/Rakefile.rb @@ -56,7 +56,7 @@ end task :build_pkg => :yard -task :teamcity => [ +task :default => [ :spec, :yard, :build_pkg, diff --git a/atv/atv.gemspec b/atv/atv.gemspec index 1090831..b75d78c 100644 --- a/atv/atv.gemspec +++ b/atv/atv.gemspec @@ -2,15 +2,14 @@ require "gpkg/gem_specification" lib = File.expand_path("../lib", __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) -require "gentex/gems/atv/version" Gpkg.gem_specification do |gpkg| gpkg.name = "gems/atv" - gpkg.version = Gentex::Gems::Atv::VERSION - gpkg.authors = ["TODO: Write your name"] - gpkg.email = ["TODO: Write your email address"] - gpkg.summary = %q{TODO: Write a short summary. Required.} - gpkg.description = %q{TODO: Write a longer description. Optional.} + gpkg.version = "1.0.0" + gpkg.authors = ["Mike Lowis"] + gpkg.email = ["mike@mdlowis.com"] + gpkg.summary = %q{Websocket server that simulates a TV station} + gpkg.description = %q{Websocket server that simulates a TV station} gpkg.homepage = "" gpkg.licenses = ["Nonstandard"] @@ -20,8 +19,6 @@ Gpkg.gem_specification do |gpkg| gpkg.test_files = gpkg.files.grep(%r{^(test|spec|features)/}) gpkg.require_paths = ["lib"] - gpkg.add_gpkg_dependency "gpkg", ">= 1.16", "< 99.0" - gpkg.add_gpkg_development_dependency "gems/teamcity_utils", "~> 1.3" gpkg.add_development_dependency "json", "~> 2.0" gpkg.add_development_dependency "rspec", "~> 3.0" gpkg.add_development_dependency "simplecov", "~> 0.9" diff --git a/atv/bin/atv b/atv/bin/atv new file mode 100755 index 0000000..f7a63f2 --- /dev/null +++ b/atv/bin/atv @@ -0,0 +1,15 @@ +#!/bin/env ruby + +require 'atv/database' +require 'atv/channel' +require 'atv/player' +require 'atv/server' + +db = ATV::Database.new(ENV["ETV_ROOT"] || "/var/www/atv") +channels = [ + ATV::Channel.new('Everything', db, + ["Movies", "Shorts", "Shows"]) +] +player = ATV::Player.new(db, channels) +server = ATV::Server.new(player) +server.start diff --git a/atv/lib/atv/channel.rb b/atv/lib/atv/channel.rb new file mode 100644 index 0000000..3c63716 --- /dev/null +++ b/atv/lib/atv/channel.rb @@ -0,0 +1,33 @@ +module ATV + class Channel + def initialize(name, db, selectors = []) + @time = 0 + @index = 0 + @db = db + files = db.files + @items = selectors.map do |sel| + files.select {|f| f["path"].start_with? sel } + end.flatten.shuffle + end + + def update(playing) + @time += 1 if playing + item = @items[@index] + if @time >= item["duration"] then + next() + pp @items[@index] + true + else + false + end + end + + def next() + @time = 0 + @index += 1 + if @index >= @items.length + @index = 0 + end + end + end +end diff --git a/atv/lib/atv/database.rb b/atv/lib/atv/database.rb new file mode 100644 index 0000000..7afdceb --- /dev/null +++ b/atv/lib/atv/database.rb @@ -0,0 +1,54 @@ +require 'json' + +module ATV + class Database + CMD="ffprobe -show_entries format=duration -v quiet -of csv=\"p=0\" -i" + + def initialize(root) + @root = root + @path = "#{root}/index.json" + @data = {} + load() + end + + def load() + if File.exist? @path + @data = JSON.parse(File.read(@path)) + else + scan() + save() + end + end + + def save() + File.open(@path, "wb") do |f| + puts f + f.write JSON.dump(@data) + end + end + + def files + @data.keys.map do |f| + @data[f].merge({ "path" => f }) + end + end + + def [](key) + @data[key] + end + + def cleanup() + files.each do |f| + @db.delete(f) if not File.exist?(f) + end + end + + def scan() + Dir.glob("#{@path}/**/*.{mp4,webm,ogg}").each do |f| + next if @data[f] + duration = `#{CMD} \"#{f}\"`.chomp.to_f + @data[f] = { "duration" => duration } + end + end + end +end diff --git a/atv/lib/atv/player.rb b/atv/lib/atv/player.rb new file mode 100644 index 0000000..1709e1a --- /dev/null +++ b/atv/lib/atv/player.rb @@ -0,0 +1,43 @@ +module ATV + class Player + def initialize(db, channels) + @db = db + @channel = 0 + @channels = channels + @playing = true + end + + def update() + updated = false + @channels.each do |c| + updated ||= c.update(@playing) + end + end + + def play() + @playing = true + end + + def pause() + @playing = false + end + + def skip() + @channels[@channel].next + end + + def chan_next() + @channel += 1 + if @channel >= @channels.length then + @channel = 0 + end + end + + def chan_prev() + @channel -= 1 + if @channel < 0 then + @channel = @channels.length - 1 + end + end + end +end diff --git a/atv/lib/atv/server.rb b/atv/lib/atv/server.rb new file mode 100644 index 0000000..e81b8a8 --- /dev/null +++ b/atv/lib/atv/server.rb @@ -0,0 +1,24 @@ +require 'iodine' + +module ATV + class Server + APP = Proc.new do |env| + if env['rack.upgrade?'.freeze] == :websocket + env['rack.upgrade'.freeze] = ATV + [0,{}, []] # It's possible to set cookies for the response. + end + end + + def initialize(player) + @player = player + end + + def start() + Iodine.listen(service: :http, handler: APP) + Iodine.run_every(1000) do + @player.update + end + Iodine.start + end + end +end diff --git a/atv/lib/database.rb b/atv/lib/database.rb deleted file mode 100644 index 3b66f4d..0000000 --- a/atv/lib/database.rb +++ /dev/null @@ -1,47 +0,0 @@ -class Database - CMD="ffprobe -show_entries format=duration -v quiet -of csv=\"p=0\" -i" - - def initialize(root) - @root = root - @path = "#{root}/index.json" - @data = {} - load(path) - end - - def load(path) - if File.exist? @path - @data = JSON.parse(File.read(@path)) - end - end - - def save() - File.open(@path, "wb") do |f| - f.write JSON.dump(@data) - end - end - - def reload() - end - - def files - @data.keys - end - - def [](key) - @data[key] - end - - def cleanup() - files.each do |f| - @db.delete(f) if not File.exist?(f) - end - end - - def scan() - Dir.glob("#{@path}/**/*.{mp4,webm,ogg}").each do |f| - next if @data[f] - duration = `#{CMD} \"#{f}\"`.chomp.to_f - @data[f] = { "duration" => duration } - end - end -end diff --git a/atv/spec/database_spec.rb b/atv/spec/database_spec.rb new file mode 100644 index 0000000..591b97e --- /dev/null +++ b/atv/spec/database_spec.rb @@ -0,0 +1,4 @@ +require "atv/database" + +describe ATV::Database do +end diff --git a/atv/spec/spec_helper.rb b/atv/spec/spec_helper.rb index f60708e..62e4cd3 100644 --- a/atv/spec/spec_helper.rb +++ b/atv/spec/spec_helper.rb @@ -11,5 +11,3 @@ SimpleCov.start do command_name "RSpec" end end - -require "gentex/gems/atv" -- 2.55.0