How to upload files to bunnyCDN storage zone using retrofit kotlin Android?

174 Views Asked by At

I want to upload a video to BunnyCDN using Retrofit in Android Kotlin, but getting crashes and error is not specified properly in Android Studio. Where I have made the mistake

Here is the documentation

[https://docs.bunny.net/reference/put_-storagezonename-path-filename][1]

Here is my all code.

In Main Activity

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private val REQUEST_CODE: Int = 0
    private lateinit var uploadViewModel : VideoUploadViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        uploadViewModel = ViewModelProvider(this).get(VideoUploadViewModel::class.java)

        val  contact = registerForActivityResult(ActivityResultContracts.GetContent()){
            binding.videoUri.text = it.toString()
            uploadVideoToBunnyCDN(it!!)
        }

        binding.selectVideoBtn.setOnClickListener{
            contact.launch("video/*")
        }

        uploadViewModel.videoUploadLiveData.observe(this) {
            Log.i("message", it.message.toString())
        }

    }

    private fun uploadVideoToBunnyCDN(it: Uri) {
        val file = File(it.path) // Get the file from the Uri
        val mediaType = "application/octet-stream".toMediaTypeOrNull()
        val requestBody = RequestBody.create(mediaType, file)
        Log.i("VIDEO_DATA_", requestBody.contentType().toString())
        uploadViewModel.uploadVideo("assam-storage-zone","myFolder","videNew", requestBody)
    }

}

ViewModel Class

@HiltViewModel
class VideoUploadViewModel @Inject constructor(private val repository: Repository) : ViewModel(){

    val videoUploadLiveData get() = repository.statusLiveData

     fun uploadVideo(storageZoneName: String,
                            folderName: String,
                            fileName: String,
                            file: RequestBody) {

        viewModelScope.launch {
                 repository.uploadVideo(storageZoneName, folderName, fileName, file)
        }
    }

}

Repository class

class Repository @Inject constructor(private val uploadApi: UploadApi)  {

    private val _statusLiveData = MutableLiveData<NetworkResult<Pair<Boolean, String>>>()
    val statusLiveData get() = _statusLiveData

    suspend fun uploadVideo(storageZoneName: String,
                            folderName: String,
                            fileName: String,
                            file: RequestBody
    ) {
        _statusLiveData.postValue(NetworkResult.Loading())
        val response = uploadApi.uploadVideo(storageZoneName, folderName, fileName, file)
        handleResponse(response, "Video Uploaded")
    }

    private fun handleResponse(response: Response<VideoUploadResponse>, message: String) {
        if (response.isSuccessful && response.body() != null) {
            _statusLiveData.postValue(NetworkResult.Success(Pair(true, message)))
        } else {
            _statusLiveData.postValue(NetworkResult.Success(Pair(false, "Something went wrong")))
        }
    }

}

Interface

interface UploadApi {

    @Multipart
    @PUT("/{storageZoneName}/{path}/{fileName}")
    fun uploadVideo(
        @Path("storageZoneName") storageZoneName: String,
        @Path("path") folderName: String,
        @Path("fileName") fileName: String,
        @Body videoData: RequestBody
    )
            : Response<VideoUploadResponse>

}

AuthInterceptor class

class AuthInterceptor @Inject constructor(): Interceptor {

    /*This will observe the request and add modification before sending the request*/
    override fun intercept(chain: Interceptor.Chain): Response {

        /*This will give us a new request object that we will be modified*/
        val request = chain.request().newBuilder()

        request.addHeader("AccessKey", "my access key")
        request.addHeader("content-type", "application/octet-stream")

        //return the modified request
        return chain.proceed(request.build())
    }
}

NetworkModule class

@InstallIn(SingletonComponent::class)
@Module
class NetworkModule {

    /*This function will be used by hilt to create Retrofit object.  Called by hilt*/
    @Singleton
    @Provides
    fun providesRetrofitBuilder(): Retrofit.Builder{
        return Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("https://storage.bunnycdn.com/")

    }

    @Singleton
    @Provides
    fun providesOkhttpClient(authInterceptor: AuthInterceptor) : OkHttpClient {
        return OkHttpClient.Builder().addInterceptor(authInterceptor).build()
    }


    @Singleton
    @Provides
    fun providesNoteAPI(retrofitBuilder: Retrofit.Builder, okHttpClient: OkHttpClient) : UploadApi{
        return retrofitBuilder
            .client(okHttpClient)
            .build()
            .create(UploadApi::class.java)
    }

}

VideoUploadResponse class

data class VideoUploadResponse(
    val message: String,
    val HttpCode: Boolean
)

NetworkResult class

 sealed class NetworkResult<T>(val data: T?= null, val message: String?= null){
        class Success<T>(data: T): NetworkResult<T>(data)
        class Error<T>(message: String?, data: T?= null): NetworkResult<T>(data, message)
        class Loading<T> : NetworkResult<T>()
    }
0

There are 0 best solutions below