kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Extend OpenSubsonic support with Transcode Offset extension
rodzic
d673e77dff
commit
6491a946c8
|
@ -916,14 +916,14 @@ class Upload(models.Model):
|
|||
# Not using reverse because this is slow
|
||||
return self.listen_url + "&download=false"
|
||||
|
||||
def get_transcoded_version(self, format, max_bitrate=None):
|
||||
def get_transcoded_version(self, format, max_bitrate=None, time_offset=None):
|
||||
if format:
|
||||
mimetype = utils.EXTENSION_TO_MIMETYPE[format]
|
||||
else:
|
||||
mimetype = self.mimetype or "audio/mpeg"
|
||||
format = utils.MIMETYPE_TO_EXTENSION[mimetype]
|
||||
|
||||
existing_versions = self.versions.filter(mimetype=mimetype)
|
||||
existing_versions = self.versions.filter(mimetype=mimetype, time_offset=time_offset)
|
||||
if max_bitrate is not None:
|
||||
# we don't want to transcode if a 320kbps version is available
|
||||
# and we're requestiong 300kbps
|
||||
|
@ -936,18 +936,24 @@ class Upload(models.Model):
|
|||
# we found an existing version, no need to transcode again
|
||||
return existing_versions[0]
|
||||
|
||||
return self.create_transcoded_version(mimetype, format, bitrate=max_bitrate)
|
||||
return self.create_transcoded_version(mimetype, format, bitrate=max_bitrate, time_offset=time_offset)
|
||||
|
||||
@transaction.atomic
|
||||
def create_transcoded_version(self, mimetype, format, bitrate):
|
||||
def create_transcoded_version(self, mimetype, format, bitrate, time_offset):
|
||||
# we create the version with an empty file, then
|
||||
# we'll write to it
|
||||
f = ContentFile(b"")
|
||||
bitrate = min(bitrate or 320000, self.bitrate or 320000)
|
||||
version = self.versions.create(mimetype=mimetype, bitrate=bitrate, size=0)
|
||||
version = self.versions.create(mimetype=mimetype, bitrate=bitrate, time_offset=time_offset, size=0)
|
||||
|
||||
if time_offset is not None:
|
||||
time_offset_filename = "-" + str(time_offset)
|
||||
else:
|
||||
time_offset_filename = ""
|
||||
|
||||
# we keep the same name, but we update the extension
|
||||
new_name = (
|
||||
os.path.splitext(os.path.basename(self.audio_file.name))[0] + f".{format}"
|
||||
os.path.splitext(os.path.basename(self.audio_file.name))[0] + time_offset_filename + f".{format}"
|
||||
)
|
||||
version.audio_file.save(new_name, f)
|
||||
utils.transcode_audio(
|
||||
|
@ -955,6 +961,7 @@ class Upload(models.Model):
|
|||
output=version.audio_file,
|
||||
output_format=utils.MIMETYPE_TO_EXTENSION[mimetype],
|
||||
bitrate=str(bitrate),
|
||||
time_offset=time_offset,
|
||||
)
|
||||
version.size = version.audio_file.size
|
||||
version.save(update_fields=["size"])
|
||||
|
@ -1002,10 +1009,11 @@ class UploadVersion(models.Model):
|
|||
accessed_date = models.DateTimeField(null=True, blank=True)
|
||||
audio_file = models.FileField(upload_to=get_file_path, max_length=255)
|
||||
bitrate = models.PositiveIntegerField()
|
||||
time_offset = models.IntegerField(null=True, blank=True)
|
||||
size = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ("upload", "mimetype", "bitrate")
|
||||
unique_together = ("upload", "mimetype", "bitrate", "time_offset")
|
||||
|
||||
@property
|
||||
def filename(self) -> str:
|
||||
|
|
|
@ -108,7 +108,10 @@ def transcode_file(input, output, input_format=None, output_format="mp3", **kwar
|
|||
return transcode_audio(audio, output, output_format, **kwargs)
|
||||
|
||||
|
||||
def transcode_audio(audio, output, output_format, **kwargs):
|
||||
def transcode_audio(audio, output, output_format, time_offset=None, **kwargs):
|
||||
if time_offset is not None:
|
||||
audio = audio[time_offset:]
|
||||
|
||||
with output.open("wb"):
|
||||
return audio.export(output, format=output_format, **kwargs)
|
||||
|
||||
|
|
|
@ -501,7 +501,7 @@ def get_file_path(audio_file):
|
|||
return path.encode("utf-8")
|
||||
|
||||
|
||||
def should_transcode(upload, format, max_bitrate=None):
|
||||
def should_transcode(upload, format, max_bitrate=None, time_offset=None):
|
||||
if not preferences.get("music__transcoding_enabled"):
|
||||
return False
|
||||
format_need_transcoding = True
|
||||
|
@ -552,7 +552,7 @@ def record_downloads(f):
|
|||
|
||||
@record_downloads
|
||||
def handle_serve(
|
||||
upload, user, format=None, max_bitrate=None, proxy_media=True, download=True
|
||||
upload, user, format=None, max_bitrate=None, time_offset=None, proxy_media=True, download=True
|
||||
):
|
||||
f = upload
|
||||
# we update the accessed_date
|
||||
|
@ -593,8 +593,8 @@ def handle_serve(
|
|||
file_path = get_file_path(f.source.replace("file://", "", 1))
|
||||
mt = f.mimetype
|
||||
|
||||
if should_transcode(f, format, max_bitrate=max_bitrate):
|
||||
transcoded_version = f.get_transcoded_version(format, max_bitrate=max_bitrate)
|
||||
if should_transcode(f, format, max_bitrate=max_bitrate, time_offset=time_offset):
|
||||
transcoded_version = f.get_transcoded_version(format, max_bitrate=max_bitrate, time_offset=time_offset)
|
||||
transcoded_version.accessed_date = now
|
||||
transcoded_version.save(update_fields=["accessed_date"])
|
||||
f = transcoded_version
|
||||
|
|
|
@ -189,7 +189,10 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
|||
)
|
||||
def get_open_subsonic_extensions(self, request, *args, **kwargs):
|
||||
data = {
|
||||
"openSubsonicExtensions": [{"name": "formPost", "versions": [1]}],
|
||||
"openSubsonicExtensions": [
|
||||
{"name": "formPost", "versions": [1]},
|
||||
{"name": "transcodeOffset", "versions": [1]}
|
||||
],
|
||||
}
|
||||
return response.Response(data, status=200)
|
||||
|
||||
|
@ -309,6 +312,15 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
|||
if max_bitrate:
|
||||
max_bitrate = max_bitrate * 1000
|
||||
|
||||
time_offset = data.get("timeOffset")
|
||||
try:
|
||||
time_offset = int(time_offset) or None
|
||||
except (TypeError, ValueError):
|
||||
time_offset = None
|
||||
|
||||
if time_offset:
|
||||
time_offset = time_offset * 1000
|
||||
|
||||
format = data.get("format") or None
|
||||
if max_bitrate and not format:
|
||||
# specific bitrate requested, but no format specified
|
||||
|
@ -323,6 +335,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
|
|||
user=request.user,
|
||||
format=format,
|
||||
max_bitrate=max_bitrate,
|
||||
time_offset=time_offset,
|
||||
# Subsonic clients don't expect 302 redirection unfortunately,
|
||||
# So we have to proxy media files
|
||||
proxy_media=True,
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
Extend Subsonic API with OpenSubsonic support (#2270)
|
||||
Extend OpenSubsonic support with Transcode Offset extension
|
||||
|
|
Ładowanie…
Reference in New Issue