Download video(s) (first iteration) (#5)
* Updated package.json (and made an excuse to make a branch) * Video filepath parser (#6) * Restructured files; Added parser placeholder * More restructuring * Added basic parser for hydrating template strings * Improved docs * More docs * Initial implementation of media profiles (#7) * [WIP] Added basic video download method * [WIP] Very-WIP first steps at parsing options and downloading * Made my options safe by default and removed special safe versions * Ran html generator for mediaprofile model - leaving as-is for now * Addressed a bunch of TODO comments * Add "channel" type Media Source (#8) * [WIP] Working on fetching channel metadata in yt-dlp backend * Finished first draft of methods to do with querying channels * Renamed CommandRunnerMock to have a more descriptive name * Ran the phx generator for the channel model * Renamed Downloader namespace to MediaClient * [WIP] saving before attempting LiveView * LiveView did not work out but here's a working controller how about * Index a channel (#9) * Ran a MediaItem generator; Reformatted to my liking * [WIP] added basic index function * setup oban * Added basic Oban job for indexing * Added in workers for indexing; hooked them into record creation flow * Added a task model with a phx generator * Tied together tasks with jobs and channels * Download indexed videos (#10) * Clarified documentation * more comments * [WIP] hooked up basic video downloading; starting work on metadata * Added metadata model and parsing Adding the metadata model made me realize that, in many cases, yt-dlp returns undesired input in stdout, breaking parsing. In order to get the metadata model working, I had to change the way in which the app interacts with yt-dlp. Now, output is written as a file to disk which is immediately re-read and returned. * Added tests for video download worker * Hooked up video downloading to the channel indexing pipeline * Adds tasks for media items * Updated video metadata parser to extract the title * Ran linting
This commit is contained in:
@@ -0,0 +1,211 @@
|
||||
defmodule Pinchflat.TasksTest do
|
||||
use Pinchflat.DataCase
|
||||
import Pinchflat.JobFixtures
|
||||
import Pinchflat.TasksFixtures
|
||||
import Pinchflat.MediaFixtures
|
||||
import Pinchflat.MediaSourceFixtures
|
||||
|
||||
alias Pinchflat.Tasks
|
||||
alias Pinchflat.Tasks.Task
|
||||
alias Pinchflat.JobFixtures.TestJobWorker
|
||||
|
||||
@invalid_attrs %{job_id: nil}
|
||||
|
||||
describe "schema" do
|
||||
test "it deletes a task when the job gets deleted" do
|
||||
task = Repo.preload(task_fixture(), [:job])
|
||||
|
||||
{:ok, _} = Repo.delete(task.job)
|
||||
|
||||
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(task) end
|
||||
end
|
||||
|
||||
test "it does not delete the other record when a job gets deleted" do
|
||||
task = Repo.preload(task_fixture(), [:channel, :job])
|
||||
|
||||
{:ok, _} = Repo.delete(task.job)
|
||||
|
||||
assert Repo.reload!(task.channel)
|
||||
end
|
||||
end
|
||||
|
||||
describe "list_tasks/0" do
|
||||
test "it returns all tasks" do
|
||||
task = task_fixture()
|
||||
assert Tasks.list_tasks() == [task]
|
||||
end
|
||||
end
|
||||
|
||||
describe "list_tasks_for/3" do
|
||||
test "it lets you specify which record type/ID to join on" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id) == [task]
|
||||
end
|
||||
|
||||
test "it lets you specify which job states to include" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id, [:available]) == [task]
|
||||
assert Tasks.list_tasks_for(:channel_id, task.channel_id, [:cancelled]) == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "list_pending_tasks_for/2" do
|
||||
test "it lists pending tasks" do
|
||||
task = task_fixture()
|
||||
|
||||
assert Tasks.list_pending_tasks_for(:channel_id, task.channel_id) == [task]
|
||||
end
|
||||
|
||||
test "it does not list non-pending tasks" do
|
||||
task = Repo.preload(task_fixture(), :job)
|
||||
:ok = Oban.cancel_job(task.job)
|
||||
|
||||
assert Tasks.list_pending_tasks_for(:channel_id, task.channel_id) == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_task!/1" do
|
||||
test "it returns the task with given id" do
|
||||
task = task_fixture()
|
||||
assert Tasks.get_task!(task.id) == task
|
||||
end
|
||||
end
|
||||
|
||||
describe "create_task/1" do
|
||||
test "creation with valid data creates a task" do
|
||||
valid_attrs = %{job_id: job_fixture().id}
|
||||
|
||||
assert {:ok, %Task{} = _task} = Tasks.create_task(valid_attrs)
|
||||
end
|
||||
|
||||
test "creation with invalid data returns error changeset" do
|
||||
assert {:error, %Ecto.Changeset{}} = Tasks.create_task(@invalid_attrs)
|
||||
end
|
||||
|
||||
test "accepts a job and channel" do
|
||||
job = job_fixture()
|
||||
channel = channel_fixture()
|
||||
|
||||
assert {:ok, %Task{} = task} = Tasks.create_task(job, channel)
|
||||
|
||||
assert task.job_id == job.id
|
||||
assert task.channel_id == channel.id
|
||||
end
|
||||
|
||||
test "accepts a job and media item" do
|
||||
job = job_fixture()
|
||||
media_item = media_item_fixture()
|
||||
|
||||
assert {:ok, %Task{} = task} = Tasks.create_task(job, media_item)
|
||||
|
||||
assert task.job_id == job.id
|
||||
assert task.media_item_id == media_item.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "create_job_with_task/2" do
|
||||
test "it enqueues the given job" do
|
||||
media_item = media_item_fixture()
|
||||
|
||||
refute_enqueued(worker: TestJobWorker)
|
||||
assert {:ok, %Task{}} = Tasks.create_job_with_task(TestJobWorker.new(%{}), media_item)
|
||||
assert_enqueued(worker: TestJobWorker)
|
||||
end
|
||||
|
||||
test "it creates a task record if successful" do
|
||||
channel = channel_fixture()
|
||||
|
||||
assert {:ok, %Task{} = task} = Tasks.create_job_with_task(TestJobWorker.new(%{}), channel)
|
||||
|
||||
assert task.channel_id == channel.id
|
||||
end
|
||||
|
||||
test "it returns an error if the job already exists" do
|
||||
channel = channel_fixture()
|
||||
job = TestJobWorker.new(%{foo: "bar"}, unique: [period: :infinity])
|
||||
|
||||
assert {:ok, %Task{}} = Tasks.create_job_with_task(job, channel)
|
||||
assert {:error, :duplicate_job} = Tasks.create_job_with_task(job, channel)
|
||||
end
|
||||
|
||||
test "it returns an error if the job fails to enqueue" do
|
||||
channel = channel_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} = Tasks.create_job_with_task(%Ecto.Changeset{}, channel)
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_task/1" do
|
||||
test "deletion deletes the task" do
|
||||
task = task_fixture()
|
||||
assert {:ok, %Task{}} = Tasks.delete_task(task)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
|
||||
test "deletion also cancels the attached job" do
|
||||
task = Repo.preload(task_fixture(), :job)
|
||||
|
||||
assert {:ok, %Task{}} = Tasks.delete_task(task)
|
||||
job = Repo.reload!(task.job)
|
||||
|
||||
assert job.state == "cancelled"
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_tasks_for/1" do
|
||||
test "it deletes tasks attached to a channel" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
|
||||
assert :ok = Tasks.delete_tasks_for(channel)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
|
||||
test "it deletes the tasks attached to a media_item" do
|
||||
media_item = media_item_fixture()
|
||||
task = task_fixture(media_item_id: media_item.id)
|
||||
|
||||
assert :ok = Tasks.delete_tasks_for(media_item)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_pending_tasks_for/1" do
|
||||
test "it deletes pending tasks attached to a channel" do
|
||||
channel = channel_fixture()
|
||||
task = task_fixture(channel_id: channel.id)
|
||||
|
||||
assert :ok = Tasks.delete_pending_tasks_for(channel)
|
||||
assert_raise Ecto.NoResultsError, fn -> Tasks.get_task!(task.id) end
|
||||
end
|
||||
|
||||
test "it does not delete non-pending tasks" do
|
||||
channel = channel_fixture()
|
||||
task = Repo.preload(task_fixture(channel_id: channel.id), :job)
|
||||
:ok = Oban.cancel_job(task.job)
|
||||
|
||||
assert :ok = Tasks.delete_pending_tasks_for(channel)
|
||||
assert Tasks.get_task!(task.id)
|
||||
end
|
||||
|
||||
test "it works on media_items" do
|
||||
media_item = media_item_fixture()
|
||||
pending_task = task_fixture(media_item_id: media_item.id)
|
||||
cancelled_task = Repo.preload(task_fixture(media_item_id: media_item.id), :job)
|
||||
:ok = Oban.cancel_job(cancelled_task.job)
|
||||
|
||||
assert :ok = Tasks.delete_pending_tasks_for(media_item)
|
||||
assert Tasks.get_task!(cancelled_task.id)
|
||||
assert_raise Ecto.NoResultsError, fn -> Repo.reload!(pending_task) end
|
||||
end
|
||||
end
|
||||
|
||||
describe "change_task/1" do
|
||||
test "it returns a task changeset" do
|
||||
task = task_fixture()
|
||||
assert %Ecto.Changeset{} = Tasks.change_task(task)
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user