Skip to content

0.1.0 #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 121 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
121 commits
Select commit Hold shift + click to select a range
945393b
WIP
xBaank Jul 18, 2024
3ed1b78
Update Readme.md
xBaank Jul 18, 2024
32d587f
Add seek for keyboard only
xBaank Jul 19, 2024
b14df0f
Merge branch 'dev' of https://github.com/xBaank/YtConsole into dev
xBaank Jul 19, 2024
95644e3
Update Readme.md
xBaank Jul 19, 2024
a3047eb
Skip on error
xBaank Jul 19, 2024
aa4e259
Merge branch 'dev' of https://github.com/xBaank/YtConsole into dev
xBaank Jul 19, 2024
8606023
Add other loop states
xBaank Jul 20, 2024
c60d15a
Update Readme.md
xBaank Jul 20, 2024
8bc32fc
Update Readme.md
xBaank Jul 21, 2024
bd79c37
Update Readme.md
xBaank Jul 21, 2024
2fb77e3
Add simple test
xBaank Jul 21, 2024
88446b9
Merge branch 'dev' of https://github.com/xBaank/YtConsole into dev
xBaank Jul 21, 2024
9cd9425
Fix test
xBaank Jul 21, 2024
481c2dc
Try to fix for env
xBaank Jul 21, 2024
ebadf1f
WIP
xBaank Jul 21, 2024
bdb63e6
More tests
xBaank Jul 21, 2024
43e30a6
Fix
xBaank Jul 21, 2024
8e640cf
Move files
xBaank Jul 21, 2024
ccd6507
Fix errors
xBaank Jul 21, 2024
1d4c9a1
Remove Array allocations and use Array pool
xBaank Jul 23, 2024
3812359
Reduce loading time
xBaank Jul 23, 2024
4329b44
WIP
xBaank Jul 23, 2024
efed884
Change skip order
xBaank Jul 23, 2024
49cdd6e
Merge branch 'main' into dev
xBaank Jul 23, 2024
b002a52
Add error code
xBaank Jul 23, 2024
b21d9c1
Use null device (default)
xBaank Jul 23, 2024
9030e98
WIP
xBaank Jul 23, 2024
fa5e495
WIP
xBaank Jul 23, 2024
4972e56
WIP
xBaank Jul 23, 2024
559f5b6
WIP
xBaank Jul 23, 2024
cb61e5e
WIP
xBaank Jul 23, 2024
3b0ef27
WIP
xBaank Jul 23, 2024
99439e8
WIP
xBaank Jul 23, 2024
32f77fc
WIP
xBaank Jul 23, 2024
30a1c4d
WIP
xBaank Jul 23, 2024
b393a96
WIP
xBaank Jul 23, 2024
f5f3a03
Merge branch 'main' into dev
xBaank Jul 23, 2024
fc2ce4f
WIP
xBaank Jul 23, 2024
a6e9401
Try null
xBaank Jul 23, 2024
3beede0
WIP
xBaank Jul 23, 2024
973ce0a
WIP
xBaank Jul 23, 2024
e57a1c6
Increase sleep
xBaank Jul 23, 2024
d44de45
WIP
xBaank Jul 23, 2024
499c123
WIP
xBaank Jul 23, 2024
59defab
WIP
xBaank Jul 23, 2024
6410c9f
maybe?
xBaank Jul 23, 2024
904aa4a
WIP
xBaank Jul 23, 2024
eec32a3
WIP
xBaank Jul 23, 2024
98cd241
WIP
xBaank Jul 23, 2024
d979aa8
WIP
xBaank Jul 23, 2024
ea4d479
WIP
xBaank Jul 23, 2024
a00d7e9
WIP
xBaank Jul 23, 2024
03d6e6c
WIP
xBaank Jul 23, 2024
90dd2e3
Update dotnet.yml
xBaank Jul 23, 2024
b2890e0
Update dotnet.yml
xBaank Jul 23, 2024
3b089d4
Update dotnet.yml
xBaank Jul 23, 2024
427c549
Update dotnet.yml
xBaank Jul 23, 2024
decf9e1
Update dotnet.yml
xBaank Jul 23, 2024
65a8ca4
Update dotnet.yml
xBaank Jul 23, 2024
8b5fb30
Update dotnet.yml
xBaank Jul 23, 2024
6dcab8f
Update dotnet.yml
xBaank Jul 23, 2024
1ae2e31
WIP
xBaank Jul 30, 2024
6e3cad7
WIP
xBaank Jul 30, 2024
e96d346
WIP
xBaank Jul 30, 2024
921bbaa
WIP
xBaank Jul 30, 2024
4eda961
WIP
xBaank Jul 30, 2024
7211464
Login (#7)
xBaank Jul 30, 2024
c9376e7
WIP
xBaank Jul 30, 2024
71e67f7
Add account index selector
xBaank Jul 31, 2024
0f4afc5
Add loader to playlist
xBaank Jul 31, 2024
0b00405
Update Readme.md
xBaank Aug 1, 2024
b5eea9c
Update Readme.md
xBaank Aug 1, 2024
70bbb56
Local playlists (#8)
xBaank Aug 4, 2024
e63c5ca
Update Readme.md
xBaank Aug 4, 2024
33a37d8
Portaudio (#10)
xBaank Aug 12, 2024
384309f
Use high latency
xBaank Aug 12, 2024
51c3062
WIP
Aug 13, 2024
326779c
Some info messages
xBaank Aug 13, 2024
0a1d3b4
Save volume into db
xBaank Aug 13, 2024
dee13b8
Try to fix tests
xBaank Aug 13, 2024
378638e
Fix tests
xBaank Aug 13, 2024
cab8764
Fix unresolved MyDbContext
xBaank Aug 13, 2024
5c0ef42
Reduce size (#11)
xBaank Aug 21, 2024
5b6e4e4
WIP
Aug 24, 2024
8d39634
WIP
Aug 24, 2024
2fe247d
WIP
Aug 24, 2024
64b22cf
asd
Aug 24, 2024
71a53e2
asd
Aug 24, 2024
e922bc6
Use pacakge
xBaank Aug 26, 2024
a5a45df
Cleanup
xBaank Aug 26, 2024
b601611
WIP
xBaank Aug 26, 2024
d035c24
WIP
xBaank Aug 26, 2024
ea110a4
Update Readme.md
xBaank Aug 26, 2024
23eacab
WIP
xBaank Aug 28, 2024
1e0f3da
Merge branch 'dev' of https://github.com/xBaank/YtConsole into dev
xBaank Aug 28, 2024
bebb3cb
Update dotnet.yml
xBaank Aug 28, 2024
798bb65
Update Readme.md
xBaank Aug 28, 2024
c17992b
Merge branch 'main' into dev
xBaank Aug 28, 2024
49acd87
Add realease
xBaank Aug 28, 2024
cf6b62c
Merge branch 'dev' of https://github.com/xBaank/YtConsole into dev
xBaank Aug 28, 2024
744f3cc
Add write permission
xBaank Aug 28, 2024
f7754ae
Fix permission?
xBaank Aug 28, 2024
afa829f
CI only main
xBaank Aug 28, 2024
d7503f0
Rename release file
xBaank Aug 28, 2024
ee90fcc
CD on ubuntu
xBaank Aug 28, 2024
a3baa37
Fix release naming
xBaank Aug 28, 2024
7eb67a5
Fix release naming?
xBaank Aug 28, 2024
4c50130
0.1.0-RC
xBaank Aug 28, 2024
7b430b7
More specific expression
xBaank Aug 28, 2024
248a0bc
Update Console.csproj
xBaank Aug 28, 2024
64328a5
Update Terminal.Gui
xBaank Aug 31, 2024
2151064
Remove NativeLibraryManager
xBaank Aug 31, 2024
02d0911
Fix compilation
xBaank Aug 31, 2024
8de19db
Reduce loading time
xBaank Sep 2, 2024
1ece797
Use long
xBaank Sep 2, 2024
70c6876
Update Console.csproj
xBaank Sep 6, 2024
a9ecaff
Update Console.csproj
xBaank Sep 9, 2024
c68b2a2
Update YoutubeExplodeMusic
xBaank Sep 20, 2024
06c461b
Merge
xBaank Sep 20, 2024
915fe14
Update Console.csproj
xBaank Sep 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 88 additions & 13 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,113 @@ name: .NET

on:
push:
branches: ["*"]
branches: ["main"]
tags: ["*"]
paths-ignore:
- "**.md"
pull_request:
branches: ["*"]
paths-ignore:
- "**.md"

permissions:
contents: write

jobs:
build:
runs-on: ubuntu-latest
test:
strategy:
matrix:
rid:
- win-x64
- linux-x64
- osx-arm64

runs-on: ${{ startsWith(matrix.rid, 'win-') && 'windows-latest' || startsWith(matrix.rid, 'osx-') && 'macos-latest' || 'ubuntu-latest' }}
timeout-minutes: 10

steps:
- uses: actions/checkout@v4

- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Set up PulseAudio

- name: Install dependencies
run: |
dotnet restore

- name: Build Release
run: dotnet build --configuration Release --no-restore

# Platform-specific custom steps
- name: Set up PulseAudio (Linux only)
if: matrix.rid == 'linux-x64'
run: |
sudo apt-get update
sudo apt-get install -y pulseaudio
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: |
pulseaudio --start
pactl load-module module-null-sink sink_name=VirtualSink sink_properties=device.description=Virtual_Sink
pactl set-default-sink VirtualSink
dotnet test --no-build --verbosity normal

- name: Test
run: dotnet test --verbosity normal --configuration Release
pack:
strategy:
matrix:
rid:
- win-arm64
- win-x86
- win-x64
- linux-arm64
- linux-x64
- osx-arm64
- osx-x64

runs-on: ubuntu-latest
timeout-minutes: 10

permissions:
actions: write
contents: write

steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x

- name: Publish
run: cd Console && dotnet publish -c Release -o ./output
run: cd Console && dotnet publish -c Release --runtime ${{ matrix.rid }} -o ./output

- name: Set execution permission
if: ${{ !startsWith(matrix.rid, 'win-') }}
run: chmod +x ./Console/output/Console

- name: Rename file
run: |
FILE=$(find ./Console/output -type f -name 'Console*')
if [ -f "$FILE" ]; then
FILENAME=$(basename -- "$FILE") # Extract the file name
EXTENSION="${FILENAME##*.}" # Extract the file extension
if [ "$EXTENSION" != "$FILENAME" ]; then # Check if an extension exists
mv "$FILE" "./Console/output/Console-${{ matrix.rid }}.$EXTENSION" # Rename with extension
else
mv "$FILE" "./Console/output/Console-${{ matrix.rid }}" # Rename without extension
fi
fi
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: YoutubeConsole
name: YoutubeConsole.${{ matrix.rid }}
path: ./Console/output
if-no-files-found: error

- name: Create Release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: ./Console/output/Console*


12 changes: 12 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ bld/
[Ll]og/
[Ll]ogs/

## sqlite
*.db

## libs
*.so
*.dll
*.dylib
*.a

# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
Expand All @@ -48,6 +57,9 @@ Generated\ Files/
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*

# Specific settings
launchSettings.json

# NUnit
*.VisualState.xml
TestResult.xml
Expand Down
172 changes: 76 additions & 96 deletions Console/Audio/AudioSender.cs
Original file line number Diff line number Diff line change
@@ -1,134 +1,114 @@
using System.Threading.Channels;
using OpenTK.Audio.OpenAL;
using PortAudioSharp;

namespace Console.Audio;

internal class AudioSender(int sourceId, ALFormat targetFormat) : IAsyncDisposable
internal class AudioSender(float volume, PlayState initialState) : IAsyncDisposable
{
private readonly Channel<PcmPacket> _queue = Channel.CreateBounded<PcmPacket>(50);
private readonly Channel<PcmPacket<short>> _queue = Channel.CreateBounded<PcmPacket<short>>(
500
);
public readonly int SampleRate = 48000;
public readonly int Channels = 2;
private readonly int[] _buffers = AL.GenBuffers(50);
private bool _clearBuffer = false;
public PlayState State { get; set; } = initialState;
public float Volume { get; set; } = volume;
public TimeSpan CurrentTime { get; private set; } = default;
public TaskCompletionSource WaitForEmptyBuffer { get; set; } = new();
private PortAudioSharp.Stream? _stream;

public void ClearBuffer()
{
_clearBuffer = true;
while (_queue.Reader.TryRead(out var next))
{
next.Dispose();
}
}

public async ValueTask Add(PcmPacket data) => await _queue.Writer.WriteAsync(data);
public async ValueTask Add(PcmPacket<short> data) => await _queue.Writer.WriteAsync(data);

private async ValueTask ClearBufferAL(CancellationToken token)
public unsafe void StartSending(CancellationToken token = default)
{
AL.GetSource(sourceId, ALGetSourcei.SourceState, out int initialState);
// Define a callback delegate for audio processing
StreamCallbackResult callback(
IntPtr input,
IntPtr output,
UInt32 frameCount,
ref StreamCallbackTimeInfo timeInfo,
StreamCallbackFlags statusFlags,
IntPtr userData
)
{
var sizeInBytes = (int)frameCount * 2;

AL.SourceStop(sourceId);
AL.GetSource(sourceId, ALGetSourcei.BuffersQueued, out int queuedCount);
if (token.IsCancellationRequested)
return StreamCallbackResult.Abort;

if (queuedCount > 0)
{
int[] bufferIds = new int[queuedCount];
AL.SourceUnqueueBuffers(sourceId, queuedCount, bufferIds);
foreach (var buffer in bufferIds)
if (State == PlayState.Paused)
{
using var next = await _queue.Reader.ReadAsync(token);
AL.BufferData(buffer, targetFormat, next.Data, SampleRate);
AL.SourceQueueBuffer(sourceId, buffer);
var spanUnmanagedBuffer = new Span<short>(output.ToPointer(), sizeInBytes);
spanUnmanagedBuffer.Clear();
return StreamCallbackResult.Continue;
}
}

_clearBuffer = false;

if ((ALSourceState)initialState == ALSourceState.Playing)
{
AL.SourcePlay(sourceId);
}

if ((ALSourceState)initialState == ALSourceState.Paused)
{
AL.SourcePlay(sourceId);
AL.SourcePause(sourceId);
}
}

public async Task StartSending(CancellationToken token = default)
{
var fillBuffers = await _queue
.Reader.ReadAllAsync(token)
.Take(10)
.ToListAsync(cancellationToken: token);

for (int i = 0; i < fillBuffers.Count; i++)
{
using var item = fillBuffers[i];
AL.BufferData(_buffers[i], targetFormat, item.Data, SampleRate);
AL.SourceQueueBuffer(sourceId, _buffers[i]);
}
if (State == PlayState.Stopped)
return StreamCallbackResult.Abort;

var _ = Task.Run(
async () =>
if (_queue.Reader.TryRead(out var nextBuffer))
{
try
{
while (!token.IsCancellationRequested)
{
if (_clearBuffer)
{
await ClearBufferAL(token);
continue;
}

AL.GetSource(
sourceId,
ALGetSourcei.BuffersProcessed,
out int releasedCount
);

if (releasedCount > 0)
{
int[] bufferIds = new int[releasedCount];
AL.SourceUnqueueBuffers(sourceId, releasedCount, bufferIds);
foreach (var buffer in bufferIds)
{
using var next = await _queue.Reader.ReadAsync(token);
AL.BufferData(buffer, targetFormat, next.Data, SampleRate);
AL.SourceQueueBuffer(sourceId, buffer);
}
}

AL.GetSource(sourceId, ALGetSourcei.SourceState, out int stateInt);
using var buffer = nextBuffer;
var spanUnmanagedBuffer = new Span<short>(output.ToPointer(), sizeInBytes);
var source = buffer.Data[..sizeInBytes];

if ((ALSourceState)stateInt == ALSourceState.Stopped)
{
AL.SourcePlay(sourceId);
}

await Task.Delay(100);
}
}
finally
for (var i = 0; i < source.Length; i++)
{
await ClearBufferAL(token);
source[i] = (short)(source[i] * Volume);
}
},
token

source.CopyTo(spanUnmanagedBuffer);
CurrentTime = buffer.Time;
return StreamCallbackResult.Continue;
}
else
{
WaitForEmptyBuffer.TrySetResult();
var spanUnmanagedBuffer = new Span<short>(output.ToPointer(), sizeInBytes);
spanUnmanagedBuffer.Clear();
return StreamCallbackResult.Continue;
}
}

StreamParameters param = new();
var deviceIndex = PortAudio.DefaultOutputDevice;
var info = PortAudio.GetDeviceInfo(deviceIndex);
param.device = PortAudio.DefaultOutputDevice;
param.channelCount = Channels;
param.sampleFormat = SampleFormat.Int16;
param.suggestedLatency = info.defaultHighOutputLatency;
param.hostApiSpecificStreamInfo = IntPtr.Zero;

_stream = new PortAudioSharp.Stream(
inParams: null,
outParams: param,
streamFlags: StreamFlags.ClipOff,
sampleRate: SampleRate,
framesPerBuffer: 960, //TODO This should not be hardcoded maybe?
callback: callback,
userData: IntPtr.Zero
);

AL.SourcePlay(sourceId);
_stream.Start();
}

public ValueTask DisposeAsync()
{
ClearBuffer();
AL.SourceStop(sourceId);
AL.GetSource(sourceId, ALGetSourcei.BuffersProcessed, out int releasedCount);
int[] bufferIds = new int[releasedCount];
AL.SourceUnqueueBuffers(sourceId, releasedCount, bufferIds);
AL.DeleteBuffers(bufferIds);
State = PlayState.Stopped;
try
{
_stream?.Stop();
_stream?.Dispose();
}
catch { }
return ValueTask.CompletedTask;
}
}
9 changes: 6 additions & 3 deletions Console/Audio/Containers/Matroska/HttpSegmentedStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

public static ValueTask<HttpSegmentedStream> Create(
public static async ValueTask<HttpSegmentedStream> Create(
IDownloadUrlHandler downloadUrlHandler,
long initialPos = 0
)
{
var httpClient = new HttpClient();
return ValueTask.FromResult(
new HttpSegmentedStream(downloadUrlHandler, httpClient, initialPos, 3_000_000)
return new HttpSegmentedStream(
downloadUrlHandler,
httpClient,
initialPos,
(int)Math.Min((await downloadUrlHandler.GetSize()) / 3, 3_000_00)
);
}

Expand Down
Loading