mirror of
https://github.com/iv-org/invidious.git
synced 2024-10-01 01:25:56 -04:00
Merge branch 'iv-org:master' into main
This commit is contained in:
commit
5fdaa1bf57
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
|||||||
stable: false
|
stable: false
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Build Docker
|
- name: Build Docker
|
||||||
run: docker-compose build --build-arg release=0
|
run: docker-compose build --build-arg release=0
|
||||||
@ -103,18 +103,18 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
with:
|
with:
|
||||||
platforms: arm64
|
platforms: arm64
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build Docker ARM64 image
|
- name: Build Docker ARM64 image
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile.arm64
|
file: docker/Dockerfile.arm64
|
||||||
|
12
.github/workflows/container-release.yml
vendored
12
.github/workflows/container-release.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Crystal
|
- name: Install Crystal
|
||||||
uses: crystal-lang/install-crystal@v1.8.0
|
uses: crystal-lang/install-crystal@v1.8.0
|
||||||
@ -38,15 +38,15 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
with:
|
with:
|
||||||
platforms: arm64
|
platforms: arm64
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to registry
|
- name: Login to registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: quay.io
|
registry: quay.io
|
||||||
username: ${{ secrets.QUAY_USERNAME }}
|
username: ${{ secrets.QUAY_USERNAME }}
|
||||||
@ -54,7 +54,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Docker AMD64 image for Push Event
|
- name: Build and push Docker AMD64 image for Push Event
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile
|
file: docker/Dockerfile
|
||||||
@ -67,7 +67,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Build and push Docker ARM64 image for Push Event
|
- name: Build and push Docker ARM64 image for Push Event
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
file: docker/Dockerfile.arm64
|
file: docker/Dockerfile.arm64
|
||||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v5
|
- uses: actions/stale@v8
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
days-before-stale: 365
|
days-before-stale: 365
|
||||||
|
@ -40,7 +40,7 @@ services:
|
|||||||
- invidious-db
|
- invidious-db
|
||||||
|
|
||||||
invidious-db:
|
invidious-db:
|
||||||
image: docker.io/library/postgres:13
|
image: docker.io/library/postgres:14
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
volumes:
|
volumes:
|
||||||
- postgresdata:/var/lib/postgresql/data
|
- postgresdata:/var/lib/postgresql/data
|
||||||
|
@ -33,7 +33,7 @@ RUN if [[ "${release}" == 1 ]] ; then \
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
FROM alpine:3.18
|
FROM alpine:3.18
|
||||||
RUN apk add --no-cache librsvg ttf-opensans tini
|
RUN apk add --no-cache rsvg-convert ttf-opensans tini
|
||||||
WORKDIR /invidious
|
WORKDIR /invidious
|
||||||
RUN addgroup -g 1000 -S invidious && \
|
RUN addgroup -g 1000 -S invidious && \
|
||||||
adduser -u 1000 -S invidious -G invidious
|
adduser -u 1000 -S invidious -G invidious
|
||||||
|
@ -33,7 +33,7 @@ RUN if [[ "${release}" == 1 ]] ; then \
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
FROM alpine:3.18
|
FROM alpine:3.18
|
||||||
RUN apk add --no-cache librsvg ttf-opensans tini
|
RUN apk add --no-cache rsvg-convert ttf-opensans tini
|
||||||
WORKDIR /invidious
|
WORKDIR /invidious
|
||||||
RUN addgroup -g 1000 -S invidious && \
|
RUN addgroup -g 1000 -S invidious && \
|
||||||
adduser -u 1000 -S invidious -G invidious
|
adduser -u 1000 -S invidious -G invidious
|
||||||
|
@ -18,8 +18,8 @@ record AboutChannel,
|
|||||||
|
|
||||||
def get_about_info(ucid, locale) : AboutChannel
|
def get_about_info(ucid, locale) : AboutChannel
|
||||||
begin
|
begin
|
||||||
# "EgVhYm91dA==" is the base64-encoded protobuf object {"2:string":"about"}
|
# Fetch channel information from channel home page
|
||||||
initdata = YoutubeAPI.browse(browse_id: ucid, params: "EgVhYm91dA==")
|
initdata = YoutubeAPI.browse(browse_id: ucid, params: "")
|
||||||
rescue
|
rescue
|
||||||
raise InfoException.new("Could not get channel info.")
|
raise InfoException.new("Could not get channel info.")
|
||||||
end
|
end
|
||||||
|
@ -208,3 +208,20 @@ def proxy_file(response, env)
|
|||||||
IO.copy response.body_io, env.response
|
IO.copy response.body_io, env.response
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Fetch the playback requests tracker from the statistics endpoint.
|
||||||
|
#
|
||||||
|
# Creates a new tracker when unavailable.
|
||||||
|
def get_playback_statistic
|
||||||
|
if (tracker = Invidious::Jobs::StatisticsRefreshJob::STATISTICS["playback"]) && tracker.as(Hash).empty?
|
||||||
|
tracker = {
|
||||||
|
"totalRequests" => 0_i64,
|
||||||
|
"successfulRequests" => 0_i64,
|
||||||
|
"ratio" => 0_f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
Invidious::Jobs::StatisticsRefreshJob::STATISTICS["playback"] = tracker
|
||||||
|
end
|
||||||
|
|
||||||
|
return tracker.as(Hash(String, Int64 | Float64))
|
||||||
|
end
|
||||||
|
@ -18,6 +18,13 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob
|
|||||||
"updatedAt" => Time.utc.to_unix,
|
"updatedAt" => Time.utc.to_unix,
|
||||||
"lastChannelRefreshedAt" => 0_i64,
|
"lastChannelRefreshedAt" => 0_i64,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# "totalRequests" => 0_i64,
|
||||||
|
# "successfulRequests" => 0_i64
|
||||||
|
# "ratio" => 0_i64
|
||||||
|
#
|
||||||
|
"playback" => {} of String => Int64 | Float64,
|
||||||
}
|
}
|
||||||
|
|
||||||
private getter db : DB::Database
|
private getter db : DB::Database
|
||||||
@ -30,7 +37,7 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob
|
|||||||
|
|
||||||
loop do
|
loop do
|
||||||
refresh_stats
|
refresh_stats
|
||||||
sleep 1.minute
|
sleep 10.minute
|
||||||
Fiber.yield
|
Fiber.yield
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -56,5 +63,8 @@ class Invidious::Jobs::StatisticsRefreshJob < Invidious::Jobs::BaseJob
|
|||||||
"updatedAt" => Time.utc.to_unix,
|
"updatedAt" => Time.utc.to_unix,
|
||||||
"lastChannelRefreshedAt" => Invidious::Database::Statistics.channel_last_update.try &.to_unix || 0_i64,
|
"lastChannelRefreshedAt" => Invidious::Database::Statistics.channel_last_update.try &.to_unix || 0_i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Reset playback requests tracker
|
||||||
|
STATISTICS["playback"] = {} of String => Int64 | Float64
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -6,6 +6,22 @@ module Invidious::Routes::API::V1::Misc
|
|||||||
if !CONFIG.statistics_enabled
|
if !CONFIG.statistics_enabled
|
||||||
return {"software" => SOFTWARE}.to_json
|
return {"software" => SOFTWARE}.to_json
|
||||||
else
|
else
|
||||||
|
# Calculate playback success rate
|
||||||
|
if (tracker = Invidious::Jobs::StatisticsRefreshJob::STATISTICS["playback"]?)
|
||||||
|
tracker = tracker.as(Hash(String, Int64 | Float64))
|
||||||
|
|
||||||
|
if !tracker.empty?
|
||||||
|
total_requests = tracker["totalRequests"]
|
||||||
|
success_count = tracker["successfulRequests"]
|
||||||
|
|
||||||
|
if total_requests.zero?
|
||||||
|
tracker["ratio"] = 1_i64
|
||||||
|
else
|
||||||
|
tracker["ratio"] = (success_count / (total_requests)).round(2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return Invidious::Jobs::StatisticsRefreshJob::STATISTICS.to_json
|
return Invidious::Jobs::StatisticsRefreshJob::STATISTICS.to_json
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -80,9 +80,14 @@ module Invidious::Routes::VideoPlayback
|
|||||||
# Remove the Range header added previously.
|
# Remove the Range header added previously.
|
||||||
headers.delete("Range") if range_header.nil?
|
headers.delete("Range") if range_header.nil?
|
||||||
|
|
||||||
|
playback_statistics = get_playback_statistic()
|
||||||
|
playback_statistics["totalRequests"] += 1
|
||||||
|
|
||||||
if response.status_code >= 400
|
if response.status_code >= 400
|
||||||
env.response.content_type = "text/plain"
|
env.response.content_type = "text/plain"
|
||||||
haltf env, response.status_code
|
haltf env, response.status_code
|
||||||
|
else
|
||||||
|
playback_statistics["successfulRequests"] += 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if url.includes? "&file=seg.ts"
|
if url.includes? "&file=seg.ts"
|
||||||
|
@ -78,6 +78,11 @@ def extract_video_info(video_id : String, proxy_region : String? = nil)
|
|||||||
# YouTube may return a different video player response than expected.
|
# YouTube may return a different video player response than expected.
|
||||||
# See: https://github.com/TeamNewPipe/NewPipe/issues/8713
|
# See: https://github.com/TeamNewPipe/NewPipe/issues/8713
|
||||||
# Line to be reverted if one day we solve the video not available issue.
|
# Line to be reverted if one day we solve the video not available issue.
|
||||||
|
|
||||||
|
# Although technically not a call to /videoplayback the fact that YouTube is returning the
|
||||||
|
# wrong video means that we should count it as a failure.
|
||||||
|
get_playback_statistic()["totalRequests"] += 1
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"version" => JSON::Any.new(Video::SCHEMA_VERSION.to_i64),
|
"version" => JSON::Any.new(Video::SCHEMA_VERSION.to_i64),
|
||||||
"reason" => JSON::Any.new("Can't load the video on this Invidious instance. YouTube is currently trying to block Invidious instances. <a href=\"https://github.com/iv-org/invidious/issues/3822\">Click here for more info about the issue.</a>"),
|
"reason" => JSON::Any.new("Can't load the video on this Invidious instance. YouTube is currently trying to block Invidious instances. <a href=\"https://github.com/iv-org/invidious/issues/3822\">Click here for more info about the issue.</a>"),
|
||||||
|
@ -37,7 +37,7 @@ struct YoutubeConnectionPool
|
|||||||
conn.close
|
conn.close
|
||||||
conn = HTTP::Client.new(url)
|
conn = HTTP::Client.new(url)
|
||||||
|
|
||||||
conn.family = (url.host == "www.youtube.com") ? CONFIG.force_resolve : Socket::Family::INET
|
conn.family = CONFIG.force_resolve
|
||||||
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
|
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
|
||||||
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
||||||
response = yield conn
|
response = yield conn
|
||||||
@ -52,7 +52,7 @@ struct YoutubeConnectionPool
|
|||||||
private def build_pool
|
private def build_pool
|
||||||
DB::Pool(HTTP::Client).new(initial_pool_size: 0, max_pool_size: capacity, max_idle_pool_size: capacity, checkout_timeout: timeout) do
|
DB::Pool(HTTP::Client).new(initial_pool_size: 0, max_pool_size: capacity, max_idle_pool_size: capacity, checkout_timeout: timeout) do
|
||||||
conn = HTTP::Client.new(url)
|
conn = HTTP::Client.new(url)
|
||||||
conn.family = (url.host == "www.youtube.com") ? CONFIG.force_resolve : Socket::Family::INET
|
conn.family = CONFIG.force_resolve
|
||||||
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
|
conn.family = Socket::Family::INET if conn.family == Socket::Family::UNSPEC
|
||||||
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
conn.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
||||||
conn
|
conn
|
||||||
@ -62,7 +62,7 @@ end
|
|||||||
|
|
||||||
def make_client(url : URI, region = nil)
|
def make_client(url : URI, region = nil)
|
||||||
client = HTTPClient.new(url, OpenSSL::SSL::Context::Client.insecure)
|
client = HTTPClient.new(url, OpenSSL::SSL::Context::Client.insecure)
|
||||||
client.family = (url.host == "www.youtube.com") ? CONFIG.force_resolve : Socket::Family::UNSPEC
|
client.family = CONFIG.force_resolve
|
||||||
client.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
client.before_request { |r| add_yt_headers(r) } if url.host == "www.youtube.com"
|
||||||
client.read_timeout = 10.seconds
|
client.read_timeout = 10.seconds
|
||||||
client.connect_timeout = 10.seconds
|
client.connect_timeout = 10.seconds
|
||||||
|
Loading…
Reference in New Issue
Block a user